"""
Test that all strategies can execute analyze_topic() with mocked dependencies.

This is Level 3 testing - verifying the main method works without crashing.
"""

import pytest
from loguru import logger
from unittest.mock import Mock

from .conftest import FACTORY_STRATEGY_NAMES


# Strategies known to have complex requirements or be experimental
SLOW_STRATEGIES = [
    "evidence",
    "constrained",
    "parallel-constrained",
    "early-stop-constrained",
    "smart-query",
    "dual-confidence",
    "dual-confidence-with-rejection",
    "concurrent-dual-confidence",
    "constraint-parallel",
    "modular",
    "modular-parallel",
    "browsecomp",
    "browsecomp-entity",
]

# Core strategies that should definitely work
CORE_STRATEGIES = [
    "source-based",
    "rapid",
    "parallel",
    "iterdrag",
    "standard",
    "news",
    "recursive",
]


class TestCoreStrategiesAnalyzeTopic:
    """Test analyze_topic for core strategies that should definitely work."""

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_analyze_topic_returns_dict(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test that analyze_topic returns a dict with expected keys."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=strategy_mock_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        try:
            result = strategy.analyze_topic("What is artificial intelligence?")

            # Should return a dict
            assert isinstance(result, dict), (
                f"{strategy_name} returned {type(result)} instead of dict"
            )

            # Should have key attributes (may vary by strategy)
            # Most strategies should return at least these
            logger.info(f"{strategy_name} returned keys: {list(result.keys())}")

            # Verify commonly expected keys
            if "error" in result:
                logger.warning(
                    f"{strategy_name} returned with error: {result.get('error')}"
                )

        except Exception as e:
            pytest.fail(
                f"{strategy_name}.analyze_topic failed: {type(e).__name__}: {e}"
            )

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_analyze_topic_with_progress_callback(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test that progress callbacks are called during analyze_topic."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=strategy_mock_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        callback = Mock()
        strategy.set_progress_callback(callback)

        try:
            strategy.analyze_topic("Test query")

            # Callback should have been called at least once
            if callback.call_count > 0:
                logger.info(
                    f"{strategy_name} called progress callback {callback.call_count} times"
                )
            else:
                logger.warning(
                    f"{strategy_name} never called progress callback"
                )

        except Exception as e:
            pytest.fail(f"{strategy_name} failed with callback: {e}")


class TestAllStrategiesAnalyzeTopic:
    """Test analyze_topic for all factory strategies."""

    @pytest.mark.parametrize("strategy_name", FACTORY_STRATEGY_NAMES)
    def test_analyze_topic_does_not_crash(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """
        Test that analyze_topic doesn't crash for any strategy.

        This test documents which strategies work and which have issues,
        without failing the entire test suite.
        """
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        try:
            strategy = create_strategy(
                strategy_name=strategy_name,
                model=strategy_mock_llm,
                search=strategy_mock_search,
                settings_snapshot=strategy_settings_snapshot,
            )

            result = strategy.analyze_topic(
                "Test query for strategy validation"
            )

            # Success - log what we got
            assert isinstance(result, dict), (
                f"Expected dict, got {type(result)}"
            )

            keys = list(result.keys())
            logger.info(
                f"[OK] {strategy_name}: returned {len(keys)} keys: {keys[:5]}..."
            )

            # Check for error in result
            if "error" in result and result["error"]:
                logger.warning(
                    f"[WARN] {strategy_name} returned error: {result['error']}"
                )

        except AttributeError as e:
            # Log attribute errors - often indicate missing mock methods
            logger.exception(f"[ATTR ERROR] {strategy_name}")
            pytest.skip(f"{strategy_name} has attribute issues: {e}")

        except TypeError as e:
            # Type errors often indicate constructor or method signature issues
            logger.exception(f"[TYPE ERROR] {strategy_name}")
            pytest.skip(f"{strategy_name} has type issues: {e}")

        except Exception as e:
            # Other exceptions - log for analysis
            logger.exception(f"[ERROR] {strategy_name}: {type(e).__name__}")
            pytest.skip(f"{strategy_name} failed: {type(e).__name__}: {e}")


class TestAnalyzeTopicReturnStructure:
    """Test the structure of analyze_topic return values."""

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_result_has_findings_key(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test that result contains 'findings' key."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=strategy_mock_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        result = strategy.analyze_topic("Test query")

        # findings key should exist (may be empty list)
        assert "findings" in result or "error" in result, (
            f"{strategy_name} missing 'findings' key. Keys: {list(result.keys())}"
        )

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_result_has_current_knowledge(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test that result contains current_knowledge."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=strategy_mock_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        result = strategy.analyze_topic("Test query")

        # Should have current_knowledge (the synthesized answer)
        if "error" not in result:
            assert "current_knowledge" in result, (
                f"{strategy_name} missing 'current_knowledge'. Keys: {list(result.keys())}"
            )


class TestLinksAccumulation:
    """Test that strategies properly accumulate links."""

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_links_populated_after_analyze(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test that all_links_of_system is populated after analyze_topic."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=strategy_mock_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        # Start empty
        assert len(strategy.all_links_of_system) == 0

        strategy.analyze_topic("Test query")

        # After search, should have some links (from mock search results)
        logger.info(
            f"{strategy_name} accumulated {len(strategy.all_links_of_system)} links"
        )


class TestQuestionsTracking:
    """Test that strategies track generated questions."""

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_questions_by_iteration_populated(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test that questions_by_iteration is populated."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=strategy_mock_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        result = strategy.analyze_topic("Test query")

        # Should have questions tracked
        questions = strategy.questions_by_iteration
        logger.info(
            f"{strategy_name} tracked {len(questions)} iterations of questions"
        )

        # Result may also contain questions
        if "questions_by_iteration" in result:
            logger.info(
                f"Result contains questions_by_iteration with {len(result['questions_by_iteration'])} iterations"
            )


class TestErrorHandling:
    """Test strategy behavior when search returns errors or empty results."""

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_handles_empty_search_results(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_settings_snapshot,
    ):
        """Test that strategy handles empty search results gracefully."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        # Mock search that returns empty results
        empty_search = Mock()
        empty_search.run = Mock(return_value=[])
        empty_search.include_full_content = True

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=empty_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        try:
            result = strategy.analyze_topic("Test query with no results")

            # Should not crash - may return error or empty findings
            assert isinstance(result, dict)
            logger.info(
                f"{strategy_name} handled empty results: {list(result.keys())}"
            )

        except Exception as e:
            pytest.fail(f"{strategy_name} crashed on empty results: {e}")

    @pytest.mark.parametrize(
        "strategy_name", CORE_STRATEGIES[:3]
    )  # Test subset
    def test_handles_search_exception(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_settings_snapshot,
    ):
        """Test that strategy handles search exceptions gracefully."""
        from local_deep_research.search_system_factory import (
            create_strategy,
        )

        # Mock search that raises an exception
        error_search = Mock()
        error_search.run = Mock(side_effect=Exception("Search API error"))
        error_search.include_full_content = True

        strategy = create_strategy(
            strategy_name=strategy_name,
            model=strategy_mock_llm,
            search=error_search,
            settings_snapshot=strategy_settings_snapshot,
        )

        try:
            result = strategy.analyze_topic("Test query")

            # Should handle the error gracefully
            assert isinstance(result, dict)

            # Should indicate an error occurred
            if "error" in result:
                logger.info(
                    f"{strategy_name} returned error: {result['error']}"
                )

        except Exception as e:
            # Some strategies may propagate the error
            logger.warning(f"{strategy_name} propagated error: {e}")


class TestSearchSystemIntegration:
    """Test analyze_topic through AdvancedSearchSystem."""

    @pytest.mark.parametrize("strategy_name", CORE_STRATEGIES)
    def test_search_system_analyze_topic(
        self,
        strategy_name: str,
        strategy_mock_llm,
        strategy_mock_search,
        strategy_settings_snapshot,
    ):
        """Test analyze_topic through the full AdvancedSearchSystem."""
        from local_deep_research.search_system import AdvancedSearchSystem

        system = AdvancedSearchSystem(
            llm=strategy_mock_llm,
            search=strategy_mock_search,
            strategy_name=strategy_name,
            settings_snapshot=strategy_settings_snapshot,
        )

        result = system.analyze_topic("Test query")

        assert isinstance(result, dict)
        assert "search_system" in result  # AdvancedSearchSystem adds this
        assert result["search_system"] == system

        logger.info(f"SearchSystem with {strategy_name}: {list(result.keys())}")
