"""Tests for _create_full_search_wrapper in search_engine_factory.py.

The wrapper now receives engine_config (with registry-injected module/class
data) directly instead of re-extracting it from the settings snapshot.
"""

from unittest.mock import Mock, patch

import pytest

from local_deep_research.web_search_engines.search_engine_factory import (
    _create_full_search_wrapper,
)


@pytest.fixture
def base_engine():
    """Provide a mock base engine."""
    return Mock()


@pytest.fixture
def mock_llm():
    """Provide a mock LLM."""
    return Mock()


class TestWrapperCreationConditions:
    """Tests for when the wrapper is and isn't created."""

    def test_wrapper_returns_base_engine_when_no_full_search_config(
        self, base_engine, mock_llm
    ):
        """Missing full_search_module/class in engine_config -> returns base engine."""
        engine_config = {
            "class_name": "TestEngine",
            # No full_search_module or full_search_class
        }

        result = _create_full_search_wrapper(
            "test_engine",
            base_engine,
            engine_config,
            mock_llm,
            {},
        )

        assert result is base_engine

    def test_wrapper_returns_base_engine_on_exception(
        self, base_engine, mock_llm
    ):
        """Exception in wrapper creation -> fallback to base engine."""
        engine_config = {
            "full_search_module": ".engines.full_search",
            "full_search_class": "FullSearchResults",
        }

        with patch(
            "local_deep_research.web_search_engines.search_engine_factory.get_safe_module_class",
            side_effect=ImportError("module not found"),
        ):
            result = _create_full_search_wrapper(
                "test_engine",
                base_engine,
                engine_config,
                mock_llm,
                {},
            )

        assert result is base_engine


class _FakeWrapperAcceptsAll:
    """Fake wrapper class that accepts specific init params."""

    def __init__(self, llm=None, web_search=None):
        self.llm = llm
        self.web_search = web_search


class _FakeWrapperWithApiKey:
    """Fake wrapper class that accepts api_key and llm."""

    def __init__(self, api_key=None, llm=None):
        self.api_key = api_key
        self.llm = llm


class TestWrapperParameterFiltering:
    """Tests for parameter filtering during wrapper creation."""

    def test_wrapper_filters_init_params(self, base_engine, mock_llm):
        """Only params accepted by wrapper __init__ are passed."""
        engine_config = {
            "full_search_module": ".engines.full_search",
            "full_search_class": "FullSearchResults",
        }

        params = {
            "llm": mock_llm,
            "web_search": base_engine,
            "unsupported_param": "should_be_filtered",
            "another_unsupported": 42,
        }

        with patch(
            "local_deep_research.web_search_engines.search_engine_factory.get_safe_module_class",
            return_value=_FakeWrapperAcceptsAll,
        ):
            result = _create_full_search_wrapper(
                "test_engine",
                base_engine,
                engine_config,
                mock_llm,
                params,
            )

        assert isinstance(result, _FakeWrapperAcceptsAll)
        assert result.llm is mock_llm
        assert result.web_search is base_engine


class TestApiKeyExtraction:
    """Tests for API key extraction from settings snapshots."""

    def test_api_key_from_settings_snapshot_dict_format(
        self, base_engine, mock_llm
    ):
        """API key extraction from {"value": "key"} format in settings."""
        engine_config = {
            "full_search_module": ".engines.full_search",
            "full_search_class": "FullSearchResults",
        }
        settings_snapshot = {
            "search.engine.web.brave.api_key": {"value": "test-api-key-123"},
        }

        with patch(
            "local_deep_research.web_search_engines.search_engine_factory.get_safe_module_class",
            return_value=_FakeWrapperWithApiKey,
        ):
            result = _create_full_search_wrapper(
                "brave",
                base_engine,
                engine_config,
                mock_llm,
                {},
                settings_snapshot=settings_snapshot,
            )

        assert isinstance(result, _FakeWrapperWithApiKey)
        assert result.api_key == "test-api-key-123"

    def test_api_key_from_settings_snapshot_plain_format(
        self, base_engine, mock_llm
    ):
        """API key extraction from plain string format in settings."""
        engine_config = {
            "full_search_module": ".engines.full_search",
            "full_search_class": "FullSearchResults",
        }
        settings_snapshot = {
            "search.engine.web.brave.api_key": "plain-api-key-456",
        }

        with patch(
            "local_deep_research.web_search_engines.search_engine_factory.get_safe_module_class",
            return_value=_FakeWrapperWithApiKey,
        ):
            result = _create_full_search_wrapper(
                "brave",
                base_engine,
                engine_config,
                mock_llm,
                {},
                settings_snapshot=settings_snapshot,
            )

        assert isinstance(result, _FakeWrapperWithApiKey)
        assert result.api_key == "plain-api-key-456"

    def test_api_key_missing_from_settings(self, base_engine, mock_llm):
        """When settings key is missing, wrapper still works — API key
        may come from other sources or be optional."""
        engine_config = {
            "full_search_module": ".engines.full_search",
            "full_search_class": "FullSearchResults",
        }
        settings_snapshot = {
            # No api_key in settings
        }

        with patch(
            "local_deep_research.web_search_engines.search_engine_factory.get_safe_module_class",
            return_value=_FakeWrapperWithApiKey,
        ):
            result = _create_full_search_wrapper(
                "brave",
                base_engine,
                engine_config,
                mock_llm,
                {},
                settings_snapshot=settings_snapshot,
            )

        assert isinstance(result, _FakeWrapperWithApiKey)
        # api_key should be None since it's not in settings
        assert result.api_key is None
