"""
Tests for the Elasticsearch search engine.

Tests cover:
- Initialization with various auth methods
- Query building
- Result processing
- Error handling
"""

from unittest.mock import Mock, patch

import pytest


class TestElasticsearchSearchEngine:
    """Tests for the ElasticsearchSearchEngine class."""

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_initialization_basic_auth(self, mock_es_class):
        """Test initialization with basic authentication."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test-cluster",
            "version": {"number": "8.0.0"},
        }
        mock_es_class.return_value = mock_client

        engine = ElasticsearchSearchEngine(
            hosts=["http://localhost:9200"],
            index_name="test_index",
            username="user",
            password="pass",
            max_results=10,
        )

        mock_es_class.assert_called_once()
        call_kwargs = mock_es_class.call_args[1]
        assert call_kwargs["basic_auth"] == ("user", "pass")
        assert engine.index_name == "test_index"
        assert engine.max_results == 10

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_initialization_api_key_auth(self, mock_es_class):
        """Test initialization with API key authentication."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test-cluster",
            "version": {"number": "8.0.0"},
        }
        mock_es_class.return_value = mock_client

        ElasticsearchSearchEngine(
            hosts=["http://localhost:9200"],
            api_key="test-api-key",
        )

        call_kwargs = mock_es_class.call_args[1]
        assert call_kwargs["api_key"] == "test-api-key"

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_initialization_cloud_id(self, mock_es_class):
        """Test initialization with Elastic Cloud ID."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "cloud-cluster",
            "version": {"number": "8.0.0"},
        }
        mock_es_class.return_value = mock_client

        ElasticsearchSearchEngine(
            hosts=["http://localhost:9200"],
            cloud_id="my-cloud-deployment:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyQ=",
        )

        call_kwargs = mock_es_class.call_args[1]
        assert "cloud_id" in call_kwargs

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_initialization_connection_error(self, mock_es_class):
        """Test handling of connection errors during initialization."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.side_effect = Exception("Connection refused")
        mock_es_class.return_value = mock_client

        with pytest.raises(ConnectionError) as exc_info:
            ElasticsearchSearchEngine(hosts=["http://localhost:9200"])

        assert "Could not connect to Elasticsearch" in str(exc_info.value)

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_get_previews(self, mock_es_class):
        """Test preview generation from Elasticsearch results."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test",
            "version": {"number": "8.0"},
        }
        mock_client.search.return_value = {
            "hits": {
                "hits": [
                    {
                        "_id": "doc1",
                        "_index": "test_index",
                        "_score": 1.5,
                        "_source": {
                            "title": "Test Document",
                            "content": "This is test content for the document.",
                            "url": "https://example.com/doc1",
                        },
                        "highlight": {
                            "content": ["This is <em>test</em> content"],
                        },
                    }
                ]
            }
        }
        mock_es_class.return_value = mock_client

        engine = ElasticsearchSearchEngine(hosts=["http://localhost:9200"])
        previews = engine._get_previews("test query")

        assert len(previews) == 1
        assert previews[0]["id"] == "doc1"
        assert previews[0]["title"] == "Test Document"
        assert "<em>test</em>" in previews[0]["snippet"]
        assert previews[0]["score"] == 1.5

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_get_previews_no_highlights(self, mock_es_class):
        """Test preview generation when no highlights are returned."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test",
            "version": {"number": "8.0"},
        }
        mock_client.search.return_value = {
            "hits": {
                "hits": [
                    {
                        "_id": "doc1",
                        "_index": "test_index",
                        "_score": 1.0,
                        "_source": {
                            "title": "Test Document",
                            "content": "A" * 300,  # Long content
                        },
                    }
                ]
            }
        }
        mock_es_class.return_value = mock_client

        engine = ElasticsearchSearchEngine(hosts=["http://localhost:9200"])
        previews = engine._get_previews("test")

        assert len(previews) == 1
        # Should truncate content to 250 chars + "..."
        assert len(previews[0]["snippet"]) == 253  # 250 + "..."

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_get_full_content(self, mock_es_class):
        """Test full content retrieval."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test",
            "version": {"number": "8.0"},
        }
        mock_client.get.return_value = {
            "_source": {
                "title": "Full Document",
                "content": "Full document content here.",
                "author": "Test Author",
            }
        }
        mock_es_class.return_value = mock_client

        engine = ElasticsearchSearchEngine(hosts=["http://localhost:9200"])

        relevant_items = [{"id": "doc1", "title": "Test", "snippet": "..."}]
        results = engine._get_full_content(relevant_items)

        assert len(results) == 1
        assert results[0]["content"] == "Full document content here."
        assert results[0]["author"] == "Test Author"

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_search_by_query_string(self, mock_es_class):
        """Test query string search."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test",
            "version": {"number": "8.0"},
        }
        mock_client.search.return_value = {"hits": {"hits": []}}
        mock_client.get.return_value = {"_source": {}}
        mock_es_class.return_value = mock_client

        engine = ElasticsearchSearchEngine(hosts=["http://localhost:9200"])
        engine.search_by_query_string("title:Python AND content:programming")

        # Verify the query was built with query_string syntax
        call_args = mock_client.search.call_args
        body = call_args[1]["body"]
        assert "query_string" in body["query"]

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_search_by_dsl(self, mock_es_class):
        """Test DSL query search."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test",
            "version": {"number": "8.0"},
        }
        mock_client.search.return_value = {"hits": {"hits": []}}
        mock_es_class.return_value = mock_client

        engine = ElasticsearchSearchEngine(hosts=["http://localhost:9200"])

        dsl_query = {
            "query": {"bool": {"must": [{"match": {"content": "test"}}]}},
            "size": 5,
        }
        engine.search_by_dsl(dsl_query)

        # Verify the DSL was passed directly
        call_args = mock_client.search.call_args
        body = call_args[1]["body"]
        assert body == dsl_query

    @patch(
        "local_deep_research.web_search_engines.engines.search_engine_elasticsearch.Elasticsearch"
    )
    def test_filter_query_integration(self, mock_es_class):
        """Test that filter_query is applied to searches."""
        from local_deep_research.web_search_engines.engines.search_engine_elasticsearch import (
            ElasticsearchSearchEngine,
        )

        mock_client = Mock()
        mock_client.info.return_value = {
            "cluster_name": "test",
            "version": {"number": "8.0"},
        }
        mock_client.search.return_value = {"hits": {"hits": []}}
        mock_es_class.return_value = mock_client

        filter_query = {"term": {"status": "published"}}
        engine = ElasticsearchSearchEngine(
            hosts=["http://localhost:9200"],
            filter_query=filter_query,
        )
        engine._get_previews("test")

        # Verify filter was applied
        call_args = mock_client.search.call_args
        body = call_args[1]["body"]
        assert "bool" in body["query"]
        assert body["query"]["bool"]["filter"] == filter_query
