"""
Tests for citation_handler.py - Strategy Selection and Handler Delegation

Tests cover:
- Handler instantiation based on type
- Alias mappings (browsecomp -> forced, simpleqa -> precision)
- Fallback behavior for unknown types
- Proper delegation to underlying handlers

These tests ensure the correct citation handler is selected for different use cases.
"""

from unittest.mock import MagicMock, patch


class TestHandlerInstantiation:
    """Tests for handler instantiation based on type."""

    def test_standard_handler_creates(self):
        """'standard' creates StandardCitationHandler."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm, handler_type="standard")

            mock_handler_class.assert_called_once()
            assert handler._handler == mock_handler

    def test_forced_handler_creates(self):
        """'forced' creates ForcedAnswerCitationHandler."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm, handler_type="forced")

            mock_handler_class.assert_called_once()
            assert handler._handler == mock_handler

    def test_precision_handler_creates(self):
        """'precision' creates PrecisionExtractionHandler."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm, handler_type="precision")

            mock_handler_class.assert_called_once()
            assert handler._handler == mock_handler

    def test_browsecomp_alias(self):
        """'browsecomp' maps to ForcedAnswerCitationHandler."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, handler_type="browsecomp")

            mock_handler_class.assert_called_once()

    def test_simpleqa_alias(self):
        """'simpleqa' maps to PrecisionExtractionHandler."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, handler_type="simpleqa")

            mock_handler_class.assert_called_once()

    def test_unknown_handler_fallback(self):
        """Unknown type falls back to standard."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, handler_type="completely_unknown_type")

            # Should fall back to standard handler
            assert mock_handler_class.call_count >= 1

    def test_handler_type_case_insensitive(self):
        """'STANDARD', 'Standard' work."""
        mock_llm = MagicMock()

        # Test uppercase
        with patch(
            "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, handler_type="FORCED")

            mock_handler_class.assert_called_once()

        # Test mixed case
        with patch(
            "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            CitationHandler(mock_llm, handler_type="Precision")

            mock_handler_class.assert_called_once()


class TestHandlerDelegation:
    """Tests for method delegation to underlying handlers."""

    def test_analyze_initial_string_input(self):
        """String search_results handled."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler.analyze_initial.return_value = {"answer": "test"}
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm)

            # Call with string input
            result = handler.analyze_initial(
                "test query", "string search results"
            )

            mock_handler.analyze_initial.assert_called_once_with(
                "test query", "string search results"
            )
            assert result == {"answer": "test"}

    def test_analyze_initial_list_input(self):
        """List of dicts handled."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler.analyze_initial.return_value = {
                "answer": "list result"
            }
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm)

            search_results = [
                {"title": "Result 1", "link": "http://example.com"},
                {"title": "Result 2", "link": "http://example2.com"},
            ]

            handler.analyze_initial("test query", search_results)

            mock_handler.analyze_initial.assert_called_once_with(
                "test query", search_results
            )

    def test_analyze_followup_params_passed(self):
        """All params passed through."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler.analyze_followup.return_value = {"followup": "result"}
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm)

            handler.analyze_followup(
                "followup question",
                [{"title": "Result", "link": "http://example.com"}],
                "previous knowledge text",
                5,
            )

            mock_handler.analyze_followup.assert_called_once_with(
                "followup question",
                [{"title": "Result", "link": "http://example.com"}],
                "previous knowledge text",
                5,
            )

    def test_handler_receives_settings_snapshot(self):
        """Settings propagated to handler."""
        mock_llm = MagicMock()
        settings = {
            "some_setting": "value",
            "another_setting": {"nested": True},
        }

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, settings_snapshot=settings)

            # Check that settings were passed to handler
            call_kwargs = mock_handler_class.call_args[1]
            assert call_kwargs["settings_snapshot"] == settings

    def test_handler_llm_instance_passed(self):
        """LLM instance correctly passed."""
        mock_llm = MagicMock()
        mock_llm.model_name = "test-model"

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm)

            # LLM should be passed as first positional arg
            call_args = mock_handler_class.call_args[0]
            assert call_args[0] == mock_llm


class TestHandlerTypeAliases:
    """Tests for all handler type aliases."""

    def test_forced_answer_alias(self):
        """'forced_answer' works."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, handler_type="forced_answer")

            mock_handler_class.assert_called_once()

    def test_precision_extraction_alias(self):
        """'precision_extraction' works."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, handler_type="precision_extraction")

            mock_handler_class.assert_called_once()


class TestBackwardCompatibility:
    """Tests for backward compatibility."""

    def test_internal_methods_exposed(self):
        """_create_documents and _format_sources exposed on handler."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_create_docs = MagicMock()
            mock_format_sources = MagicMock()

            mock_handler = MagicMock()
            mock_handler._create_documents = mock_create_docs
            mock_handler._format_sources = mock_format_sources
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            handler = CitationHandler(mock_llm)

            # These should be exposed for backward compatibility
            assert handler._create_documents == mock_create_docs
            assert handler._format_sources == mock_format_sources

    def test_default_handler_without_type(self):
        """No handler_type defaults to standard."""
        mock_llm = MagicMock()

        with patch(
            "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm)  # No handler_type specified

            mock_handler_class.assert_called_once()


class TestSettingsSnapshotHandlerType:
    """Tests for handler type from settings snapshot."""

    def test_handler_from_settings_direct_value(self):
        """Handler type from settings as direct value."""
        mock_llm = MagicMock()
        settings = {"citation.handler_type": "forced"}

        with patch(
            "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, settings_snapshot=settings)

            mock_handler_class.assert_called_once()

    def test_handler_from_settings_dict_value(self):
        """Handler type from settings as dict with value key."""
        mock_llm = MagicMock()
        settings = {"citation.handler_type": {"value": "precision"}}

        with patch(
            "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            CitationHandler(mock_llm, settings_snapshot=settings)

            mock_handler_class.assert_called_once()

    def test_explicit_type_overrides_settings(self):
        """Explicit handler_type overrides settings snapshot."""
        mock_llm = MagicMock()
        settings = {"citation.handler_type": "forced"}

        with patch(
            "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler"
        ) as mock_handler_class:
            mock_handler = MagicMock()
            mock_handler._create_documents = MagicMock()
            mock_handler._format_sources = MagicMock()
            mock_handler_class.return_value = mock_handler

            from local_deep_research.citation_handler import CitationHandler

            # Explicit type should override settings
            CitationHandler(
                mock_llm, handler_type="precision", settings_snapshot=settings
            )

            mock_handler_class.assert_called_once()
