"""
Tests for the OpenAlexSearchEngine class.

Tests cover:
- Initialization and configuration
- Email handling for polite pool
- Sort and filter options
- Preview generation
- Abstract reconstruction
- Full content retrieval
- Rate limiting
"""

from unittest.mock import Mock, patch
import pytest


# Mock JournalReputationFilter for all OpenAlex tests
@pytest.fixture(autouse=True)
def mock_journal_filter():
    """Mock JournalReputationFilter to avoid LLM initialization."""
    with patch(
        "local_deep_research.web_search_engines.engines.search_engine_openalex.JournalReputationFilter.create_default",
        return_value=None,
    ):
        yield


class TestOpenAlexSearchEngineInit:
    """Tests for OpenAlexSearchEngine initialization."""

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

        engine = OpenAlexSearchEngine()

        assert engine.max_results == 25
        assert engine.sort_by == "relevance"
        assert engine.filter_open_access is False
        assert engine.min_citations == 0
        assert engine.from_publication_date is None
        assert engine.email is None
        assert engine.api_base == "https://api.openalex.org"

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

        engine = OpenAlexSearchEngine(max_results=50)

        assert engine.max_results == 50

    def test_init_with_email(self):
        """Initialize with email for polite pool."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine(email="test@example.com")

        assert engine.email == "test@example.com"
        assert "test@example.com" in engine.headers["User-Agent"]

    def test_init_with_false_email_string(self):
        """Initialize with 'False' string email."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine(email="False")

        assert engine.email is None

    def test_init_with_sort_by(self):
        """Initialize with custom sort_by."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine(sort_by="cited_by_count")

        assert engine.sort_by == "cited_by_count"

    def test_init_with_open_access_filter(self):
        """Initialize with open access filter."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine(filter_open_access=True)

        assert engine.filter_open_access is True

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

        engine = OpenAlexSearchEngine(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_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine(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_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine(from_publication_date="False")

        assert engine.from_publication_date is None

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

        mock_llm = Mock()
        engine = OpenAlexSearchEngine(llm=mock_llm)

        assert engine.llm is mock_llm


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_openalex import (
            OpenAlexSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {
            "meta": {"count": 1},
            "results": [
                {
                    "id": "https://openalex.org/W123",
                    "display_name": "Test Paper",
                    "publication_year": 2023,
                    "publication_date": "2023-05-15",
                    "doi": "https://doi.org/10.1234/test",
                    "cited_by_count": 50,
                    "authorships": [
                        {"author": {"display_name": "John Doe"}},
                        {"author": {"display_name": "Jane Smith"}},
                    ],
                    "primary_location": {"source": {"display_name": "Nature"}},
                    "open_access": {"is_oa": True},
                    "best_oa_location": {
                        "pdf_url": "https://example.com/paper.pdf"
                    },
                    "abstract_inverted_index": {"Test": [0], "abstract": [1]},
                }
            ],
        }

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_openalex.safe_get",
            return_value=mock_response,
        ):
            engine = OpenAlexSearchEngine()
            previews = engine._get_previews("machine learning")

            assert len(previews) == 1
            assert previews[0]["title"] == "Test Paper"
            assert previews[0]["year"] == 2023
            assert previews[0]["citations"] == 50
            assert previews[0]["is_open_access"] is True
            assert "John Doe" 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_openalex import (
            OpenAlexSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {"meta": {"count": 0}, "results": []}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_openalex.safe_get",
            return_value=mock_response,
        ) as mock_get:
            engine = OpenAlexSearchEngine(
                filter_open_access=True,
                min_citations=100,
                from_publication_date="2023-01-01",
            )
            engine._get_previews("test query")

            call_kwargs = mock_get.call_args[1]
            params = call_kwargs["params"]
            assert "filter" in params
            assert "is_oa:true" in params["filter"]
            assert "cited_by_count:>100" in params["filter"]
            assert "from_publication_date:2023-01-01" in params["filter"]

    def test_get_previews_with_email(self):
        """Get previews includes email in params."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {"meta": {"count": 0}, "results": []}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_openalex.safe_get",
            return_value=mock_response,
        ) as mock_get:
            engine = OpenAlexSearchEngine(email="test@example.com")
            engine._get_previews("test query")

            call_kwargs = mock_get.call_args[1]
            params = call_kwargs["params"]
            assert params.get("mailto") == "test@example.com"

    def test_get_previews_rate_limit_error(self):
        """Get previews raises RateLimitError on 429."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )
        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_openalex.safe_get",
            return_value=mock_response,
        ):
            engine = OpenAlexSearchEngine()

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

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

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.json.return_value = {"meta": {"count": 0}, "results": []}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_openalex.safe_get",
            return_value=mock_response,
        ):
            engine = OpenAlexSearchEngine()
            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_openalex import (
            OpenAlexSearchEngine,
        )

        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_openalex.safe_get",
            return_value=mock_response,
        ):
            engine = OpenAlexSearchEngine()
            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_openalex import (
            OpenAlexSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_openalex.safe_get",
            side_effect=Exception("Connection error"),
        ):
            engine = OpenAlexSearchEngine()
            previews = engine._get_previews("test query")

            assert previews == []


class TestFormatWorkPreview:
    """Tests for _format_work_preview method."""

    def test_format_work_preview_full_data(self):
        """Format work preview with full data."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        work = {
            "id": "https://openalex.org/W123",
            "display_name": "Test Paper Title",
            "publication_year": 2023,
            "publication_date": "2023-05-15",
            "doi": "https://doi.org/10.1234/test",
            "cited_by_count": 100,
            "authorships": [
                {"author": {"display_name": "Author One"}},
                {"author": {"display_name": "Author Two"}},
            ],
            "primary_location": {"source": {"display_name": "Test Journal"}},
            "open_access": {"is_oa": True},
            "best_oa_location": {"pdf_url": "https://example.com/paper.pdf"},
            "abstract_inverted_index": {
                "This": [0],
                "is": [1],
                "abstract": [2],
            },
        }

        preview = engine._format_work_preview(work)

        assert preview["id"] == "https://openalex.org/W123"
        assert preview["title"] == "Test Paper Title"
        assert preview["year"] == 2023
        assert preview["citations"] == 100
        assert preview["journal"] == "Test Journal"
        assert preview["is_open_access"] is True
        assert "Author One" in preview["authors"]
        assert "Author Two" in preview["authors"]

    def test_format_work_preview_with_doi(self):
        """Format work preview converts DOI to URL."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        work = {
            "id": "https://openalex.org/W123",
            "display_name": "Test",
            "doi": "10.1234/test",
        }

        preview = engine._format_work_preview(work)

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

    def test_format_work_preview_many_authors(self):
        """Format work preview truncates many authors."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        work = {
            "id": "https://openalex.org/W123",
            "display_name": "Test",
            "authorships": [
                {"author": {"display_name": f"Author {i}"}} for i in range(10)
            ],
        }

        preview = engine._format_work_preview(work)

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

    def test_format_work_preview_missing_data(self):
        """Format work preview handles missing data."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        work = {"id": "https://openalex.org/W123"}

        preview = engine._format_work_preview(work)

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


class TestReconstructAbstract:
    """Tests for _reconstruct_abstract method."""

    def test_reconstruct_abstract_basic(self):
        """Reconstruct abstract from inverted index."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        inverted_index = {
            "This": [0],
            "is": [1],
            "a": [2],
            "test": [3],
            "abstract": [4],
        }

        abstract = engine._reconstruct_abstract(inverted_index)

        assert abstract == "This is a test abstract"

    def test_reconstruct_abstract_with_repeated_words(self):
        """Reconstruct abstract with repeated words."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        inverted_index = {
            "The": [0, 4],
            "cat": [1],
            "sat": [2],
            "on": [3],
            "mat": [5],
        }

        abstract = engine._reconstruct_abstract(inverted_index)

        assert abstract == "The cat sat on The mat"

    def test_reconstruct_abstract_empty(self):
        """Reconstruct abstract handles empty index."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        abstract = engine._reconstruct_abstract({})

        assert abstract == ""


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_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        items = [
            {
                "title": "Test Paper",
                "link": "https://example.com",
                "snippet": "Test snippet",
                "abstract": "Full abstract text",
                "authors": "John Doe",
                "year": 2023,
                "journal": "Nature",
                "citations": 100,
                "is_open_access": True,
                "oa_url": "https://example.com/oa",
            }
        ]

        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_openalex import (
            OpenAlexSearchEngine,
        )

        engine = OpenAlexSearchEngine()

        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):
        """OpenAlexSearchEngine is marked as public."""
        from local_deep_research.web_search_engines.engines.search_engine_openalex import (
            OpenAlexSearchEngine,
        )

        assert OpenAlexSearchEngine.is_public is True

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

        assert OpenAlexSearchEngine.is_scientific is True
