"""
Tests for Research API endpoints.

Phase 32: API Endpoint Tests - Tests for research-related API functionality.
Tests research_functions.py API methods including quick_summary and deep_research.
"""

from unittest.mock import MagicMock, patch
import pytest


class TestInitSearchSystem:
    """Tests for _init_search_system function."""

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_basic(self, mock_system_class, mock_get_llm):
        """Test basic initialization of search system."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        result = _init_search_system()

        mock_get_llm.assert_called_once()
        mock_system_class.assert_called_once()
        assert result == mock_system

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_model_name(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom model name."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        _init_search_system(model_name="gpt-4")

        call_kwargs = mock_get_llm.call_args[1]
        assert call_kwargs.get("model_name") == "gpt-4"

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_temperature(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom temperature."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        _init_search_system(temperature=0.5)

        call_kwargs = mock_get_llm.call_args[1]
        assert call_kwargs.get("temperature") == 0.5

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_provider(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom provider."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        _init_search_system(provider="anthropic")

        call_kwargs = mock_get_llm.call_args[1]
        assert call_kwargs.get("provider") == "anthropic"

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_iterations(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom iterations."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        result = _init_search_system(iterations=5)

        assert result.max_iterations == 5

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_questions_per_iteration(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom questions per iteration."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        result = _init_search_system(questions_per_iteration=3)

        assert result.questions_per_iteration == 3

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_progress_callback(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with progress callback."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        callback = MagicMock()
        _init_search_system(progress_callback=callback)

        mock_system.set_progress_callback.assert_called_once_with(callback)

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    @patch("local_deep_research.api.research_functions.get_search")
    def test_init_search_system_with_search_tool(
        self, mock_get_search, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom search tool."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system
        mock_search = MagicMock()
        mock_get_search.return_value = mock_search

        _init_search_system(search_tool="arxiv")

        mock_get_search.assert_called_once()
        call_args = mock_get_search.call_args[0]
        assert call_args[0] == "arxiv"

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    def test_init_search_system_with_search_strategy(
        self, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom search strategy."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        _init_search_system(search_strategy="modular")

        call_kwargs = mock_system_class.call_args[1]
        assert call_kwargs.get("strategy_name") == "modular"

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    @patch(
        "local_deep_research.web_search_engines.retriever_registry.retriever_registry"
    )
    def test_init_search_system_with_retrievers(
        self, mock_registry, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom retrievers."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        retrievers = {"custom": MagicMock()}
        _init_search_system(retrievers=retrievers)

        mock_registry.register_multiple.assert_called_once_with(retrievers)

    @patch("local_deep_research.api.research_functions.get_llm")
    @patch("local_deep_research.api.research_functions.AdvancedSearchSystem")
    @patch("local_deep_research.llm.register_llm")
    def test_init_search_system_with_llms(
        self, mock_register_llm, mock_system_class, mock_get_llm
    ):
        """Test initialization with custom LLMs."""
        from local_deep_research.api.research_functions import (
            _init_search_system,
        )

        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_system = MagicMock()
        mock_system_class.return_value = mock_system

        custom_llm = MagicMock()
        llms = {"custom_llm": custom_llm}
        _init_search_system(llms=llms)

        mock_register_llm.assert_called_once_with("custom_llm", custom_llm)


class TestQuickSummary:
    """Tests for quick_summary function."""

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_basic(self, mock_init_system):
        """Test basic quick summary."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary content",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        result = quick_summary("What is AI?")

        assert "summary" in result or "current_knowledge" in result
        mock_system.analyze_topic.assert_called_once()

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_with_provider(self, mock_init_system):
        """Test quick summary with custom provider in settings_snapshot."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        quick_summary("Query", provider="anthropic")

        # Provider is passed via settings_snapshot, not as a direct kwarg
        call_kwargs = mock_init_system.call_args[1]
        # Check that settings_snapshot was created and passed
        assert "settings_snapshot" in call_kwargs

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_with_temperature(self, mock_init_system):
        """Test quick summary with custom temperature in settings_snapshot."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        quick_summary("Query", temperature=0.3)

        # Temperature is passed via settings_snapshot, not as a direct kwarg
        call_kwargs = mock_init_system.call_args[1]
        # Check that settings_snapshot was created and passed
        assert "settings_snapshot" in call_kwargs

    @patch("local_deep_research.api.research_functions._init_search_system")
    @patch(
        "local_deep_research.web_search_engines.retriever_registry.retriever_registry"
    )
    def test_quick_summary_with_retrievers(
        self, mock_registry, mock_init_system
    ):
        """Test quick summary registers retrievers with registry."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        retrievers = {"custom": MagicMock()}
        quick_summary("Query", retrievers=retrievers)

        # Retrievers are registered with the registry, not passed to _init_search_system
        mock_registry.register_multiple.assert_called_once_with(retrievers)

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_with_research_id(self, mock_init_system):
        """Test quick summary with research ID tracking."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        quick_summary("Query", research_id="test-123")

        call_kwargs = mock_init_system.call_args[1]
        assert call_kwargs.get("research_id") == "test-123"

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_search_original_query_default(
        self, mock_init_system
    ):
        """Test quick summary search_original_query default is True."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        quick_summary("Query")

        call_kwargs = mock_init_system.call_args[1]
        assert call_kwargs.get("search_original_query") is True

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_search_original_query_false(self, mock_init_system):
        """Test quick summary with search_original_query disabled."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Summary",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        quick_summary("Query", search_original_query=False)

        call_kwargs = mock_init_system.call_args[1]
        assert call_kwargs.get("search_original_query") is False


class TestResearchAPIValidation:
    """Tests for API input validation."""

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_empty_query(self, mock_init_system):
        """Test quick summary with empty query."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "",
            "iterations": 0,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        # Should not raise, but may return empty results
        result = quick_summary("")
        assert result is not None

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_special_characters(self, mock_init_system):
        """Test quick summary with special characters."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Result",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        result = quick_summary("What about <script>alert('test')</script>?")
        assert result is not None

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_unicode_query(self, mock_init_system):
        """Test quick summary with unicode characters."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Result",
            "iterations": 1,
            "questions_by_iteration": {},
            "all_links_of_system": [],
        }
        mock_init_system.return_value = mock_system

        result = quick_summary("什么是人工智能？")
        assert result is not None


class TestResearchAPIErrorHandling:
    """Tests for API error handling."""

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_system_error(self, mock_init_system):
        """Test quick summary handles system errors."""
        from local_deep_research.api.research_functions import quick_summary

        mock_init_system.side_effect = Exception("System error")

        with pytest.raises(Exception):
            quick_summary("Query")

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_quick_summary_analyze_error(self, mock_init_system):
        """Test quick summary handles analyze_topic errors."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.side_effect = Exception("Analysis error")
        mock_init_system.return_value = mock_system

        with pytest.raises(Exception):
            quick_summary("Query")


class TestResearchAPIIntegration:
    """Integration tests for research API."""

    @patch("local_deep_research.api.research_functions._init_search_system")
    def test_full_research_workflow(self, mock_init_system):
        """Test complete research workflow."""
        from local_deep_research.api.research_functions import quick_summary

        mock_system = MagicMock()
        mock_system.analyze_topic.return_value = {
            "current_knowledge": "Comprehensive research results about AI",
            "iterations": 3,
            "questions_by_iteration": {1: ["Q1", "Q2"], 2: ["Q3"], 3: ["Q4"]},
            "all_links_of_system": [
                {"url": "http://source1.com", "title": "Source 1"},
                {"url": "http://source2.com", "title": "Source 2"},
            ],
        }
        mock_init_system.return_value = mock_system

        result = quick_summary(
            "What is artificial intelligence?",
            provider="openai",
            temperature=0.7,
        )

        assert result is not None
        mock_system.analyze_topic.assert_called_once()
