"""
Comprehensive tests for the PubMed search engine.
Tests initialization, search functionality, error handling, and rate limiting.
"""

import pytest
from unittest.mock import Mock


class TestPubMedSearchEngineInit:
    """Tests for PubMed search engine initialization."""

    def test_init_default_parameters(self):
        """Test initialization with default parameters."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        engine = PubMedSearchEngine()

        # Default max_results is 10, but PubMed forces minimum of 25
        assert engine.max_results >= 25
        assert engine.api_key is None
        assert engine.days_limit is None
        assert engine.get_abstracts is True
        assert engine.get_full_text is False
        assert engine.is_public is True
        assert engine.is_scientific is True

    def test_init_custom_parameters(self):
        """Test initialization with custom parameters."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        engine = PubMedSearchEngine(
            max_results=50,
            api_key="test_api_key",
            days_limit=30,
            get_abstracts=False,
            get_full_text=True,
            full_text_limit=5,
        )

        assert engine.max_results == 50
        assert engine.api_key == "test_api_key"
        assert engine.days_limit == 30
        assert engine.get_abstracts is False
        assert engine.get_full_text is True
        assert engine.full_text_limit == 5

    def test_api_urls_configured(self):
        """Test that API URLs are correctly configured."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        engine = PubMedSearchEngine()

        assert "eutils.ncbi.nlm.nih.gov" in engine.base_url
        assert "esearch.fcgi" in engine.search_url
        assert "esummary.fcgi" in engine.summary_url
        assert "efetch.fcgi" in engine.fetch_url


class TestPubMedSearchExecution:
    """Tests for PubMed search execution."""

    @pytest.fixture
    def pubmed_engine(self):
        """Create a PubMed engine instance."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        return PubMedSearchEngine(max_results=10)

    def test_search_pubmed_success(self, pubmed_engine, monkeypatch):
        """Test successful PubMed search."""
        # Mock the safe_get function
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.raise_for_status = Mock()
        mock_response.json.return_value = {
            "esearchresult": {
                "count": "2",
                "retmax": "10",
                "idlist": ["12345678", "87654321"],
            }
        }

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            lambda *args, **kwargs: mock_response,
        )

        # Call the search method
        pmids = pubmed_engine._search_pubmed("machine learning")

        assert len(pmids) == 2
        assert "12345678" in pmids
        assert "87654321" in pmids

    def test_search_pubmed_empty_results(self, pubmed_engine, monkeypatch):
        """Test PubMed search with no results."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.raise_for_status = Mock()
        mock_response.json.return_value = {
            "esearchresult": {
                "count": "0",
                "retmax": "10",
                "idlist": [],
            }
        }

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            lambda *args, **kwargs: mock_response,
        )

        pmids = pubmed_engine._search_pubmed("nonexistent query xyz123")
        assert pmids == []

    def test_search_pubmed_with_api_key(self, monkeypatch):
        """Test that API key is included in request when provided."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        engine = PubMedSearchEngine(api_key="my_test_api_key")

        # Track the params passed to safe_get
        captured_params = {}

        def mock_safe_get(url, params=None, **kwargs):
            captured_params.update(params or {})
            mock_resp = Mock()
            mock_resp.status_code = 200
            mock_resp.raise_for_status = Mock()
            mock_resp.json.return_value = {
                "esearchresult": {"count": "0", "idlist": []}
            }
            return mock_resp

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            mock_safe_get,
        )

        engine._search_pubmed("test query")
        assert captured_params.get("api_key") == "my_test_api_key"

    def test_search_pubmed_with_date_limit(self, monkeypatch):
        """Test that date limit is included in request when provided."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        engine = PubMedSearchEngine(days_limit=30)

        captured_params = {}

        def mock_safe_get(url, params=None, **kwargs):
            captured_params.update(params or {})
            mock_resp = Mock()
            mock_resp.status_code = 200
            mock_resp.raise_for_status = Mock()
            mock_resp.json.return_value = {
                "esearchresult": {"count": "0", "idlist": []}
            }
            return mock_resp

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            mock_safe_get,
        )

        engine._search_pubmed("test query")
        assert captured_params.get("reldate") == 30
        assert captured_params.get("datetype") == "pdat"


class TestPubMedErrorHandling:
    """Tests for PubMed search error handling."""

    @pytest.fixture
    def pubmed_engine(self):
        """Create a PubMed engine instance."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        return PubMedSearchEngine(max_results=10)

    def test_search_handles_network_error(self, pubmed_engine, monkeypatch):
        """Test that network errors are handled gracefully."""
        from requests.exceptions import ConnectionError

        def mock_safe_get(*args, **kwargs):
            raise ConnectionError("Network unreachable")

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            mock_safe_get,
        )

        # Should return empty list on error
        result = pubmed_engine._search_pubmed("test query")
        assert result == []

    def test_search_handles_timeout_error(self, pubmed_engine, monkeypatch):
        """Test that timeout errors are handled gracefully."""
        from requests.exceptions import Timeout

        def mock_safe_get(*args, **kwargs):
            raise Timeout("Request timed out")

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            mock_safe_get,
        )

        result = pubmed_engine._search_pubmed("test query")
        assert result == []

    def test_search_handles_http_error(self, pubmed_engine, monkeypatch):
        """Test that HTTP errors are handled gracefully."""
        from requests.exceptions import HTTPError

        mock_response = Mock()
        mock_response.status_code = 500
        mock_response.raise_for_status.side_effect = HTTPError("Server error")

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            lambda *args, **kwargs: mock_response,
        )

        result = pubmed_engine._search_pubmed("test query")
        assert result == []

    def test_search_handles_invalid_json(self, pubmed_engine, monkeypatch):
        """Test that invalid JSON responses are handled gracefully."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.raise_for_status = Mock()
        mock_response.json.side_effect = ValueError("Invalid JSON")

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            lambda *args, **kwargs: mock_response,
        )

        result = pubmed_engine._search_pubmed("test query")
        assert result == []


class TestPubMedResultCount:
    """Tests for getting result count."""

    @pytest.fixture
    def pubmed_engine(self):
        """Create a PubMed engine instance."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        return PubMedSearchEngine(max_results=10)

    def test_get_result_count_success(self, pubmed_engine, monkeypatch):
        """Test getting result count."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.raise_for_status = Mock()
        mock_response.json.return_value = {"esearchresult": {"count": "1500"}}

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            lambda *args, **kwargs: mock_response,
        )

        count = pubmed_engine._get_result_count("cancer treatment")
        assert count == 1500

    def test_get_result_count_error(self, pubmed_engine, monkeypatch):
        """Test getting result count handles errors."""
        from requests.exceptions import ConnectionError

        def mock_safe_get(*args, **kwargs):
            raise ConnectionError("Network error")

        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.search_engine_pubmed.safe_get",
            mock_safe_get,
        )

        count = pubmed_engine._get_result_count("test query")
        assert count == 0


class TestPubMedContextOptions:
    """Tests for PubMed context configuration options."""

    def test_context_options_initialization(self):
        """Test that context options are properly initialized."""
        from local_deep_research.web_search_engines.engines.search_engine_pubmed import (
            PubMedSearchEngine,
        )

        engine = PubMedSearchEngine(
            include_publication_type_in_context=False,
            include_journal_in_context=False,
            include_year_in_context=False,
            include_mesh_terms_in_context=False,
            max_mesh_terms=5,
            max_keywords=5,
        )

        assert engine.include_publication_type_in_context is False
        assert engine.include_journal_in_context is False
        assert engine.include_year_in_context is False
        assert engine.include_mesh_terms_in_context is False
        assert engine.max_mesh_terms == 5
        assert engine.max_keywords == 5
