"""
Tests for the NasaAdsSearchEngine class.

Tests cover:
- Initialization and configuration
- API key handling
- Search parameters and filters
- Preview generation
- Document formatting
- Full content retrieval
- Rate limiting
"""

from unittest.mock import Mock, patch
import pytest


# Mock JournalReputationFilter for all NASA ADS tests
@pytest.fixture(autouse=True)
def mock_journal_filter():
    """Mock JournalReputationFilter to avoid LLM initialization."""
    with patch(
        "local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
        return_value=None,
    ):
        yield


class TestNasaAdsSearchEngineInit:
    """Tests for NasaAdsSearchEngine initialization."""

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

        engine = NasaAdsSearchEngine()

        assert engine.max_results == 25
        assert engine.sort_by == "relevance"
        assert engine.min_citations == 0
        assert engine.include_arxiv is True
        assert engine.from_publication_date is None
        assert engine.api_base == "https://api.adsabs.harvard.edu/v1"

    def test_init_with_api_key(self):
        """Initialize with API key."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

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

        assert engine.api_key == "test-api-key"
        assert "Authorization" in engine.headers
        assert engine.headers["Authorization"] == "Bearer test-api-key"

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

        engine = NasaAdsSearchEngine(max_results=50)

        assert engine.max_results == 50

    def test_init_with_sort_by_citations(self):
        """Initialize with citation count sorting."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine(sort_by="citation_count")

        assert engine.sort_by == "citation_count"

    def test_init_with_min_citations(self):
        """Initialize with minimum citations filter."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine(min_citations=100)

        assert engine.min_citations == 100

    def test_init_with_from_publication_date(self):
        """Initialize with publication date filter."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine(from_publication_date="2023-01-01")

        assert engine.from_publication_date == "2023-01-01"

    def test_init_with_false_publication_date(self):
        """Initialize with 'False' string publication date."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine(from_publication_date="False")

        assert engine.from_publication_date is None

    def test_init_with_include_arxiv_disabled(self):
        """Initialize with ArXiv disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine(include_arxiv=False)

        assert engine.include_arxiv is False

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

        mock_llm = Mock()
        engine = NasaAdsSearchEngine(llm=mock_llm)

        assert engine.llm is mock_llm

    def test_init_with_false_api_key(self):
        """Initialize with 'False' string API key."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine(api_key="False")

        assert engine.api_key is None


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_nasa_ads import (
            NasaAdsSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {
            "response": {
                "numFound": 1,
                "docs": [
                    {
                        "bibcode": "2023ApJ...123..456A",
                        "title": ["Test Astrophysics Paper"],
                        "author": ["Author One", "Author Two"],
                        "year": "2023",
                        "pubdate": "2023-05-15",
                        "abstract": "This is a test abstract about astrophysics.",
                        "citation_count": 50,
                        "pub": "The Astrophysical Journal",
                        "doi": ["10.1234/test"],
                        "keyword": ["astrophysics", "cosmology"],
                    }
                ],
            }
        }

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            return_value=mock_response,
        ):
            engine = NasaAdsSearchEngine(api_key="test-key")
            previews = engine._get_previews("black holes")

            assert len(previews) == 1
            assert previews[0]["title"] == "Test Astrophysics Paper"
            assert previews[0]["year"] == "2023"
            assert previews[0]["citations"] == 50
            assert "Author One" in previews[0]["authors"]

    def test_get_previews_with_filters(self):
        """Get previews includes filters in request."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {
            "response": {"numFound": 0, "docs": []}
        }

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            return_value=mock_response,
        ) as mock_get:
            engine = NasaAdsSearchEngine(
                api_key="test-key",
                min_citations=100,
                from_publication_date="2023-01-01",
                include_arxiv=False,
            )
            engine._get_previews("test query")

            call_kwargs = mock_get.call_args[1]
            params = call_kwargs["params"]
            assert "citation_count" in params["q"]
            assert "year:2023" in params["q"]
            assert "arXiv" in params["q"]

    def test_get_previews_rate_limit_error(self):
        """Get previews raises RateLimitError on 429."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )
        from local_deep_research.web_search_engines.rate_limiting import (
            RateLimitError,
        )

        mock_response = Mock()
        mock_response.status_code = 429
        mock_response.headers = {}
        mock_response.text = "Rate limit exceeded"

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            return_value=mock_response,
        ):
            engine = NasaAdsSearchEngine(api_key="test-key")

            with pytest.raises(RateLimitError):
                engine._get_previews("test query")

    def test_get_previews_unauthorized(self):
        """Get previews handles 401 unauthorized."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 401
        mock_response.headers = {}
        mock_response.text = "Unauthorized"

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            return_value=mock_response,
        ):
            engine = NasaAdsSearchEngine(api_key="invalid-key")
            previews = engine._get_previews("test query")

            assert previews == []

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

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {
            "response": {"numFound": 0, "docs": []}
        }

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            return_value=mock_response,
        ):
            engine = NasaAdsSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert previews == []

    def test_get_previews_api_error(self):
        """Get previews handles API errors gracefully."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 500
        mock_response.headers = {}
        mock_response.text = "Internal server error"

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            return_value=mock_response,
        ):
            engine = NasaAdsSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert previews == []

    def test_get_previews_exception(self):
        """Get previews handles exceptions gracefully."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_nasa_ads.safe_get",
            side_effect=Exception("Connection error"),
        ):
            engine = NasaAdsSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert previews == []


class TestFormatDocPreview:
    """Tests for _format_doc_preview method."""

    def test_format_doc_preview_full_data(self):
        """Format doc preview with full data."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        doc = {
            "bibcode": "2023ApJ...123..456A",
            "title": ["Test Astrophysics Paper"],
            "author": ["Author One", "Author Two", "Author Three"],
            "year": "2023",
            "pubdate": "2023-05-15",
            "abstract": "This is a test abstract.",
            "citation_count": 100,
            "pub": "The Astrophysical Journal",
            "doi": ["10.1234/test"],
            "keyword": ["astrophysics", "cosmology"],
            "bibstem": ["ApJ"],
        }

        preview = engine._format_doc_preview(doc)

        assert preview["id"] == "2023ApJ...123..456A"
        assert preview["title"] == "Test Astrophysics Paper"
        assert preview["year"] == "2023"
        assert preview["citations"] == 100
        assert preview["journal"] == "The Astrophysical Journal"
        assert "Author One" in preview["authors"]
        assert preview["link"] == "https://doi.org/10.1234/test"

    def test_format_doc_preview_with_doi(self):
        """Format doc preview creates DOI URL."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        doc = {
            "bibcode": "2023Test",
            "title": ["Test"],
            "doi": ["10.1234/test"],
        }

        preview = engine._format_doc_preview(doc)

        assert preview["link"] == "https://doi.org/10.1234/test"

    def test_format_doc_preview_without_doi(self):
        """Format doc preview falls back to ADS URL."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        doc = {
            "bibcode": "2023Test",
            "title": ["Test"],
        }

        preview = engine._format_doc_preview(doc)

        assert "adsabs.harvard.edu" in preview["link"]
        assert "2023Test" in preview["link"]

    def test_format_doc_preview_many_authors(self):
        """Format doc preview truncates many authors."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        doc = {
            "bibcode": "2023Test",
            "title": ["Test"],
            "author": [f"Author {i}" for i in range(10)],
        }

        preview = engine._format_doc_preview(doc)

        assert "et al." in preview["authors"]

    def test_format_doc_preview_emits_authors_csl(self):
        """NASA ADS authors arrive as 'Last, First' — surface them as
        structured CSL so the citation normalizer doesn't re-split a
        comma-joined display string and lose the family/given pairing.
        """
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()
        doc = {
            "bibcode": "2023Test",
            "title": ["Test"],
            "author": ["Smith, John", "Doe, Jane"],
        }

        preview = engine._format_doc_preview(doc)

        assert preview["authors_csl"] == [
            {"family": "Smith", "given": "John"},
            {"family": "Doe", "given": "Jane"},
        ]
        # Display string is still comma-joined for backwards compat
        assert preview["authors"] == "Smith, John, Doe, Jane"

    def test_format_doc_preview_arxiv_detection(self):
        """Format doc preview detects ArXiv papers."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        doc = {
            "bibcode": "2023arXiv",
            "title": ["Test ArXiv Paper"],
            "bibstem": ["arXiv"],
        }

        preview = engine._format_doc_preview(doc)

        assert preview["is_arxiv"] is True

    def test_format_doc_preview_missing_data(self):
        """Format doc preview handles missing data.

        ``journal`` emits None when no ``pub``/``bibstem`` is available —
        the old ``"unknown"`` literal leaked through normalize_citation's
        container_title fallback and even matched a real OpenAlex source
        named "unknown" (h_index=5, Q1) at Tier-2 lookup. Non-journal
        fields (title, year) still use the sentinel string because
        they don't flow into journal-reputation scoring.
        """
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        doc = {"bibcode": "2023Test"}

        preview = engine._format_doc_preview(doc)

        assert preview["title"] == "No title"
        assert preview["year"] == "unknown"
        assert preview["journal"] is None


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

    def test_get_full_content_returns_items(self):
        """Get full content returns formatted items."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        items = [
            {
                "title": "Test Paper",
                "link": "https://example.com",
                "snippet": "Test snippet",
                "abstract": "Full abstract text",
                "authors": "John Doe",
                "year": "2023",
                "journal": "ApJ",
                "citations": 100,
                "is_arxiv": False,
                "keywords": ["test"],
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        assert results[0]["title"] == "Test Paper"
        assert results[0]["content"] == "Full abstract text"
        assert results[0]["metadata"]["authors"] == "John Doe"
        assert results[0]["metadata"]["citations"] == 100

    def test_get_full_content_uses_snippet_if_no_abstract(self):
        """Get full content uses snippet if no abstract."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        engine = NasaAdsSearchEngine()

        items = [
            {
                "title": "Test Paper",
                "link": "https://example.com",
                "snippet": "Test snippet",
            }
        ]

        results = engine._get_full_content(items)

        assert results[0]["content"] == "Test snippet"


class TestClassAttributes:
    """Tests for class attributes."""

    def test_is_public(self):
        """NasaAdsSearchEngine is marked as public."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        assert NasaAdsSearchEngine.is_public is True

    def test_is_scientific(self):
        """NasaAdsSearchEngine is marked as scientific."""
        from local_deep_research.web_search_engines.engines.search_engine_nasa_ads import (
            NasaAdsSearchEngine,
        )

        assert NasaAdsSearchEngine.is_scientific is True
