"""
Tests for the PaperlessSearchEngine class.

Tests cover:
- Initialization and configuration
- API authentication
- Query expansion with LLM
- Multi-pass search strategy
- Preview generation
- Full content retrieval
- Document conversion
- Connection testing
"""

from unittest.mock import Mock, patch


class TestPaperlessSearchEngineInit:
    """Tests for PaperlessSearchEngine initialization."""

    def test_init_with_defaults(self):
        """Initialize with default values."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        assert engine.max_results == 10
        assert engine.api_url == "http://localhost:8000"
        assert engine.timeout == 30
        assert engine.verify_ssl is True
        assert engine.include_content is True

    def test_init_with_api_url(self):
        """Initialize with custom API URL."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(api_url="https://paperless.example.com")

        assert engine.api_url == "https://paperless.example.com"

    def test_init_strips_trailing_slash(self):
        """Initialize strips trailing slash from API URL."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(api_url="https://paperless.example.com/")

        assert engine.api_url == "https://paperless.example.com"

    def test_init_with_api_key(self):
        """Initialize with API key sets authorization header."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(api_key="test-api-key")

        assert engine.api_token == "test-api-key"
        assert "Authorization" in engine.headers
        assert engine.headers["Authorization"] == "Token test-api-key"

    def test_init_with_api_token_backwards_compat(self):
        """Initialize with api_token parameter for backwards compatibility."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(api_token="legacy-token")

        assert engine.api_token == "legacy-token"
        assert engine.headers["Authorization"] == "Token legacy-token"

    def test_init_with_custom_max_results(self):
        """Initialize with custom max_results."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(max_results=50)

        assert engine.max_results == 50

    def test_init_with_custom_timeout(self):
        """Initialize with custom timeout."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(timeout=60)

        assert engine.timeout == 60

    def test_init_with_ssl_disabled(self):
        """Initialize with SSL verification disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(verify_ssl=False)

        assert engine.verify_ssl is False

    def test_init_with_content_disabled(self):
        """Initialize with content inclusion disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(include_content=False)

        assert engine.include_content is False

    def test_init_with_settings_snapshot(self):
        """Initialize with settings snapshot."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        settings = {
            "search.engine.web.paperless.default_params.api_url": "https://custom.paperless.com",
            "search.engine.web.paperless.api_key": "snapshot-key",
        }

        engine = PaperlessSearchEngine(settings_snapshot=settings)

        assert engine.api_url == "https://custom.paperless.com"
        assert engine.api_token == "snapshot-key"

    def test_init_with_llm(self):
        """Initialize with LLM."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_llm = Mock()
        engine = PaperlessSearchEngine(llm=mock_llm)

        assert engine.llm is mock_llm


class TestMakeRequest:
    """Tests for _make_request method."""

    def test_make_request_success(self):
        """Make request returns JSON response."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_response = Mock()
        mock_response.json.return_value = {
            "results": [{"id": 1, "title": "Test"}]
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_paperless.safe_get",
            return_value=mock_response,
        ):
            engine = PaperlessSearchEngine()
            result = engine._make_request("/api/documents/")

            assert result["results"][0]["title"] == "Test"

    def test_make_request_with_params(self):
        """Make request passes parameters."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_response = Mock()
        mock_response.json.return_value = {"results": []}
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_paperless.safe_get",
            return_value=mock_response,
        ) as mock_get:
            engine = PaperlessSearchEngine(
                api_url="http://test.com", api_key="key"
            )
            engine._make_request("/api/documents/", params={"query": "test"})

            mock_get.assert_called_once()
            call_kwargs = mock_get.call_args[1]
            assert call_kwargs["params"] == {"query": "test"}
            assert "Authorization" in call_kwargs["headers"]

    def test_make_request_exception(self):
        """Make request handles exceptions."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )
        import requests

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_paperless.safe_get",
            side_effect=requests.exceptions.RequestException(
                "Connection error"
            ),
        ):
            engine = PaperlessSearchEngine()
            result = engine._make_request("/api/documents/")

            assert result == {}


class TestExpandQueryWithLLM:
    """Tests for _expand_query_with_llm method."""

    def test_expand_query_without_llm(self):
        """Expand query returns original without LLM."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        result = engine._expand_query_with_llm("original query")

        assert result == "original query"

    def test_expand_query_with_llm(self):
        """Expand query uses LLM."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(
            content='tax OR taxes OR "tax return" OR IRS'
        )

        engine = PaperlessSearchEngine(llm=mock_llm)
        result = engine._expand_query_with_llm("tax documents")

        assert "tax" in result
        assert "OR" in result

    def test_expand_query_llm_exception(self):
        """Expand query handles LLM exception."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_llm = Mock()
        mock_llm.invoke.side_effect = Exception("LLM error")

        engine = PaperlessSearchEngine(llm=mock_llm)
        result = engine._expand_query_with_llm("original query")

        assert result == "original query"


class TestMultiPassSearch:
    """Tests for _multi_pass_search method."""

    def test_multi_pass_search_single_pass(self):
        """Multi-pass search performs initial search."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_response = {
            "results": [
                {
                    "id": 1,
                    "title": "Document 1",
                    "__search_hit__": {"score": 1.0},
                },
            ]
        }

        engine = PaperlessSearchEngine()
        with patch.object(engine, "_make_request", return_value=mock_response):
            results = engine._multi_pass_search("test query")

            assert len(results) == 1
            assert results[0]["title"] == "Document 1"

    def test_multi_pass_search_with_llm(self):
        """Multi-pass search uses LLM expansion."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(content="expanded OR query")

        pass1_response = {
            "results": [
                {"id": 1, "title": "Doc 1", "__search_hit__": {"score": 1.0}},
            ]
        }
        pass2_response = {
            "results": [
                {"id": 1, "title": "Doc 1", "__search_hit__": {"score": 1.0}},
                {"id": 2, "title": "Doc 2", "__search_hit__": {"score": 0.5}},
            ]
        }

        engine = PaperlessSearchEngine(llm=mock_llm)
        with patch.object(
            engine,
            "_make_request",
            side_effect=[pass1_response, pass2_response],
        ):
            results = engine._multi_pass_search("test")

            # Should have deduplicated results from both passes
            assert len(results) == 2

    def test_multi_pass_search_deduplicates(self):
        """Multi-pass search deduplicates by document ID."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(content="expanded")

        # Same document appears in both passes
        response = {
            "results": [
                {
                    "id": 1,
                    "title": "Same Doc",
                    "__search_hit__": {"score": 1.0},
                },
            ]
        }

        engine = PaperlessSearchEngine(llm=mock_llm)
        with patch.object(engine, "_make_request", return_value=response):
            results = engine._multi_pass_search("test")

            # Should only have one result despite appearing in both passes
            assert len(results) == 1

    def test_multi_pass_search_sorts_by_score(self):
        """Multi-pass search sorts results by relevance score."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        response = {
            "results": [
                {
                    "id": 1,
                    "title": "Low Score",
                    "__search_hit__": {"score": 0.5},
                },
                {
                    "id": 2,
                    "title": "High Score",
                    "__search_hit__": {"score": 2.0},
                },
                {
                    "id": 3,
                    "title": "Medium Score",
                    "__search_hit__": {"score": 1.0},
                },
            ]
        }

        engine = PaperlessSearchEngine()
        with patch.object(engine, "_make_request", return_value=response):
            results = engine._multi_pass_search("test")

            assert results[0]["title"] == "High Score"
            assert results[1]["title"] == "Medium Score"
            assert results[2]["title"] == "Low Score"


class TestGetPreviews:
    """Tests for _get_previews method."""

    def test_get_previews_returns_results(self):
        """Get previews returns formatted results."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        mock_search_results = [
            {
                "id": 1,
                "title": "Test Document",
                "content": "This is the content",
                "correspondent_name": "John Doe",
                "created": "2024-01-15",
                "__search_hit__": {
                    "score": 1.0,
                    "highlights": "This is the <span>content</span>",
                },
            }
        ]

        engine = PaperlessSearchEngine(api_url="http://test.com")
        with patch.object(
            engine, "_multi_pass_search", return_value=mock_search_results
        ):
            previews = engine._get_previews("test query")

            assert len(previews) == 1
            assert "Test Document" in previews[0]["title"]
            assert previews[0]["source"] == "Paperless"
            assert "http://test.com/documents/1/details" in previews[0]["url"]

    def test_get_previews_empty_results(self):
        """Get previews handles empty results."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()
        with patch.object(engine, "_multi_pass_search", return_value=[]):
            previews = engine._get_previews("test query")

            assert previews == []

    def test_get_previews_exception(self):
        """Get previews handles exceptions."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()
        with patch.object(
            engine, "_multi_pass_search", side_effect=Exception("Search error")
        ):
            previews = engine._get_previews("test query")

            assert previews == []


class TestConvertDocumentToPreview:
    """Tests for _convert_document_to_preview method."""

    def test_convert_with_full_data(self):
        """Convert document with full data."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(api_url="http://paperless.local")

        doc_data = {
            "id": 123,
            "title": "Invoice 2024",
            "content": "This is the invoice content",
            "correspondent_name": "ACME Corp",
            "document_type_name": "Invoice",
            "created": "2024-01-15",
            "modified": "2024-01-16",
            "tags_list": ["finance", "2024"],
            "__search_hit__": {
                "score": 1.5,
                "rank": 1,
                "highlights": "This is the <span>invoice</span> content",
            },
        }

        preview = engine._convert_document_to_preview(doc_data, "invoice")

        assert "ACME Corp" in preview["title"]
        assert "Invoice 2024" in preview["title"]
        assert preview["url"] == "http://paperless.local/documents/123/details"
        assert preview["author"] == "ACME Corp"
        assert preview["date"] == "2024-01-15"
        assert "invoice" in preview["snippet"]

    def test_convert_cleans_html_highlights(self):
        """Convert document cleans HTML from highlights."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        doc_data = {
            "id": 1,
            "title": "Test",
            "__search_hit__": {
                "highlights": '<span class="match">matched</span> text here',
            },
        }

        preview = engine._convert_document_to_preview(doc_data)

        assert "<span" not in preview["snippet"]
        assert "**matched**" in preview["snippet"]

    def test_convert_fallback_to_content(self):
        """Convert document falls back to content when no highlights."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        doc_data = {
            "id": 1,
            "title": "Test",
            "content": "This is the document content for testing",
        }

        preview = engine._convert_document_to_preview(doc_data, "testing")

        assert "document content" in preview["snippet"]

    def test_convert_multiple_highlights(self):
        """Convert document with multiple highlights returns list."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        doc_data = {
            "id": 1,
            "title": "Multi-highlight Doc",
            "__search_hit__": {
                "highlights": [
                    "First <span>highlight</span>",
                    "Second <span>highlight</span>",
                ],
            },
        }

        previews = engine._convert_document_to_preview(doc_data)

        # Should return a list of previews
        assert isinstance(previews, list)
        assert len(previews) == 2
        assert "excerpt 1" in previews[0]["title"]
        assert "excerpt 2" in previews[1]["title"]


class TestGetFullContent:
    """Tests for _get_full_content method."""

    def test_get_full_content_returns_items(self):
        """Get full content returns processed items."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        items = [
            {
                "title": "Test Doc",
                "url": "http://test.com/doc/1",
                "snippet": "Short snippet",
                "metadata": {"doc_id": "1"},
                "_raw_data": {"content": "This is the full document content."},
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        assert (
            results[0]["full_content"] == "This is the full document content."
        )
        assert "_raw_data" not in results[0]

    def test_get_full_content_disabled(self):
        """Get full content returns items unchanged when disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine(include_content=False)

        items = [{"title": "Test", "snippet": "Snippet"}]

        results = engine._get_full_content(items)

        assert results == items

    def test_get_full_content_fallback_to_snippet(self):
        """Get full content falls back to snippet."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        items = [
            {
                "title": "Test",
                "snippet": "This is the snippet",
                "metadata": {"doc_id": "1"},
                "_raw_data": {},  # No content in raw data
            }
        ]

        with patch.object(engine, "_make_request", return_value={}):
            results = engine._get_full_content(items)

            assert results[0]["full_content"] == "This is the snippet"


class TestRun:
    """Tests for run method."""

    def test_run_returns_results(self):
        """Run returns search results."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        mock_previews = [
            {
                "title": "Result",
                "url": "http://test.com/1",
                "snippet": "Snippet",
                "metadata": {"doc_id": "1"},
                "_raw_data": {"content": "Full content"},
            }
        ]

        with patch.object(engine, "_get_previews", return_value=mock_previews):
            results = engine.run("test query")

            assert len(results) == 1
            assert results[0]["title"] == "Result"

    def test_run_empty_results(self):
        """Run handles empty results."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(engine, "_get_previews", return_value=[]):
            results = engine.run("test query")

            assert results == []

    def test_run_exception(self):
        """Run handles exceptions."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(
            engine, "_get_previews", side_effect=Exception("Search error")
        ):
            results = engine.run("test query")

            assert results == []


class TestTestConnection:
    """Tests for test_connection method."""

    def test_connection_success(self):
        """Test connection success."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(
            engine, "_make_request", return_value={"version": "2.0"}
        ):
            result = engine.test_connection()

            assert result is True

    def test_connection_failure(self):
        """Test connection failure."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(engine, "_make_request", return_value={}):
            result = engine.test_connection()

            assert result is False

    def test_connection_exception(self):
        """Test connection handles exception."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(
            engine, "_make_request", side_effect=Exception("Connection error")
        ):
            result = engine.test_connection()

            assert result is False


class TestGetDocumentCount:
    """Tests for get_document_count method."""

    def test_get_document_count_success(self):
        """Get document count success."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(engine, "_make_request", return_value={"count": 150}):
            count = engine.get_document_count()

            assert count == 150

    def test_get_document_count_error(self):
        """Get document count returns -1 on error."""
        from local_deep_research.web_search_engines.engines.search_engine_paperless import (
            PaperlessSearchEngine,
        )

        engine = PaperlessSearchEngine()

        with patch.object(
            engine, "_make_request", side_effect=Exception("API error")
        ):
            count = engine.get_document_count()

            assert count == -1
