"""
Tests for the search_system_factory module.

These tests verify that the strategy registry is consistent with the factory.
"""

import pytest
from unittest.mock import MagicMock


class TestAvailableStrategies:
    """Tests for the AVAILABLE_STRATEGIES registry."""

    def test_available_strategies_not_empty(self):
        """Test AVAILABLE_STRATEGIES is not empty."""
        from local_deep_research.search_system_factory import (
            AVAILABLE_STRATEGIES,
        )

        assert len(AVAILABLE_STRATEGIES) > 0

    def test_available_strategies_has_required_fields(self):
        """Test each strategy has name and description."""
        from local_deep_research.search_system_factory import (
            AVAILABLE_STRATEGIES,
        )

        for strategy in AVAILABLE_STRATEGIES:
            assert "name" in strategy, f"Strategy missing 'name': {strategy}"
            assert "description" in strategy, (
                f"Strategy missing 'description': {strategy}"
            )
            assert len(strategy["name"]) > 0, "Strategy name is empty"
            assert len(strategy["description"]) > 0, (
                "Strategy description is empty"
            )

    def test_get_available_strategies_function(self):
        """Test get_available_strategies returns correct data."""
        from local_deep_research.search_system_factory import (
            get_available_strategies,
            AVAILABLE_STRATEGIES,
        )

        result = get_available_strategies()
        assert result == AVAILABLE_STRATEGIES
        # Verify it's a copy
        assert result is not AVAILABLE_STRATEGIES


class TestStrategyCreation:
    """Tests for create_strategy function."""

    @pytest.fixture
    def mock_model(self):
        """Create a mock language model."""
        model = MagicMock()
        model.invoke = MagicMock(return_value=MagicMock(content="test"))
        return model

    @pytest.fixture
    def mock_search(self):
        """Create a mock search engine."""
        search = MagicMock()
        search.run = MagicMock(return_value=[])
        return search

    def test_create_source_based_strategy(self, mock_model, mock_search):
        """Test creating source-based strategy."""
        from local_deep_research.search_system_factory import create_strategy

        strategy = create_strategy("source-based", mock_model, mock_search)
        assert strategy is not None
        assert hasattr(strategy, "analyze_topic")

    def test_create_focused_iteration_strategy(self, mock_model, mock_search):
        """Test creating focused-iteration strategy."""
        from local_deep_research.search_system_factory import create_strategy

        strategy = create_strategy("focused-iteration", mock_model, mock_search)
        assert strategy is not None

    def test_mcp_alias_routes_to_langgraph(self, mock_model, mock_search):
        """The removed 'mcp'/'agentic' keys are deprecated aliases that
        route to langgraph-agent (not the source-based fallback)."""
        from local_deep_research.search_system_factory import create_strategy

        for alias in ("mcp", "agentic"):
            strategy = create_strategy(alias, mock_model, mock_search)
            assert type(strategy).__name__ == "LangGraphAgentStrategy"

    def test_create_rapid_strategy(self, mock_model, mock_search):
        """Test creating rapid strategy."""
        from local_deep_research.search_system_factory import create_strategy

        strategy = create_strategy("rapid", mock_model, mock_search)
        assert strategy is not None

    def test_create_unknown_strategy_defaults_to_source_based(
        self, mock_model, mock_search
    ):
        """Test unknown strategy defaults to source-based."""
        from local_deep_research.search_system_factory import create_strategy

        strategy = create_strategy("unknown-strategy", mock_model, mock_search)
        assert strategy is not None
        # Should be source-based type
        assert "SourceBasedSearchStrategy" in type(strategy).__name__

    def test_strategy_names_case_insensitive(self, mock_model, mock_search):
        """Test strategy names are case insensitive."""
        from local_deep_research.search_system_factory import create_strategy

        strategy1 = create_strategy("SOURCE-BASED", mock_model, mock_search)
        strategy2 = create_strategy("source-based", mock_model, mock_search)

        assert type(strategy1).__name__ == type(strategy2).__name__

    def test_strategy_names_with_underscores(self, mock_model, mock_search):
        """Test strategy names work with underscores instead of hyphens."""
        from local_deep_research.search_system_factory import create_strategy

        strategy1 = create_strategy("source-based", mock_model, mock_search)
        strategy2 = create_strategy("source_based", mock_model, mock_search)

        assert type(strategy1).__name__ == type(strategy2).__name__


class TestStrategyRegistryConsistency:
    """Tests to verify the strategy registry matches available strategies."""

    @pytest.fixture
    def mock_model(self):
        """Create a mock language model."""
        model = MagicMock()
        model.invoke = MagicMock(return_value=MagicMock(content="test"))
        return model

    @pytest.fixture
    def mock_search(self):
        """Create a mock search engine."""
        search = MagicMock()
        search.run = MagicMock(return_value=[])
        return search

    def test_all_registered_strategies_can_be_created(
        self, mock_model, mock_search
    ):
        """Test that all strategies in AVAILABLE_STRATEGIES can be created."""
        from local_deep_research.search_system_factory import (
            AVAILABLE_STRATEGIES,
            create_strategy,
        )

        # Known issues with some strategies (pre-existing bugs)
        known_issues = {}

        for strategy_info in AVAILABLE_STRATEGIES:
            name = strategy_info["name"]
            try:
                strategy = create_strategy(name, mock_model, mock_search)
                # Should not default to source-based (except for source-based itself)
                if name != "source-based":
                    # Check it's not just defaulting
                    assert strategy is not None, (
                        f"Strategy '{name}' returned None"
                    )
            except ImportError as e:
                # Some strategies may have optional dependencies
                pytest.skip(f"Strategy '{name}' has missing dependencies: {e}")
            except TypeError as e:
                # Known parameter compatibility issues
                if name in known_issues:
                    pytest.skip(
                        f"Known issue with '{name}': {known_issues[name]}"
                    )
                else:
                    pytest.fail(f"Failed to create strategy '{name}': {e}")
            except Exception as e:
                pytest.fail(f"Failed to create strategy '{name}': {e}")

    def test_no_duplicate_strategy_names(self):
        """Test there are no duplicate strategy names in the registry."""
        from local_deep_research.search_system_factory import (
            AVAILABLE_STRATEGIES,
        )

        names = [s["name"] for s in AVAILABLE_STRATEGIES]
        duplicates = [name for name in names if names.count(name) > 1]

        assert len(duplicates) == 0, (
            f"Duplicate strategy names found: {set(duplicates)}"
        )
