"""
Comprehensive tests for the ArXiv search engine.
Tests initialization, search functionality, error handling, and sorting options.
"""

import pytest
from unittest.mock import Mock
from datetime import datetime


class TestArXivSearchEngineInit:
    """Tests for ArXiv search engine initialization."""

    @pytest.fixture(autouse=True)
    def mock_journal_filter(self, monkeypatch):
        """Mock JournalReputationFilter to avoid LLM dependency."""
        monkeypatch.setattr(
            "local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
            Mock(return_value=None),
        )

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

        engine = ArXivSearchEngine()

        # ArXiv forces minimum of 25 results
        assert engine.max_results >= 25
        assert engine.sort_by == "relevance"
        assert engine.sort_order == "descending"
        assert engine.include_full_text is False
        assert engine.download_dir is None
        assert engine.is_public is True
        assert engine.is_scientific is True
        assert engine.is_generic is False

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

        engine = ArXivSearchEngine(
            max_results=50,
            sort_by="submittedDate",
            sort_order="ascending",
            include_full_text=True,
            download_dir="/tmp/arxiv",
            max_full_text=5,
        )

        assert engine.max_results == 50
        assert engine.sort_by == "submittedDate"
        assert engine.sort_order == "ascending"
        assert engine.include_full_text is True
        assert engine.download_dir == "/tmp/arxiv"
        assert engine.max_full_text == 5

    def test_sort_criteria_mapping(self):
        """Test that sort criteria are properly mapped."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )
        import arxiv

        engine = ArXivSearchEngine()

        assert "relevance" in engine.sort_criteria
        assert "lastUpdatedDate" in engine.sort_criteria
        assert "submittedDate" in engine.sort_criteria
        assert (
            engine.sort_criteria["relevance"] == arxiv.SortCriterion.Relevance
        )


class TestArXivSearchExecution:
    """Tests for ArXiv search execution."""

    @pytest.fixture(autouse=True)
    def mock_journal_filter(self, monkeypatch):
        """Mock JournalReputationFilter to avoid LLM dependency."""
        monkeypatch.setattr(
            "local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
            Mock(return_value=None),
        )

    @pytest.fixture
    def arxiv_engine(self):
        """Create an ArXiv engine instance."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )

        return ArXivSearchEngine(max_results=10)

    def test_search_results_structure(self, arxiv_engine, monkeypatch):
        """Test that search results have correct structure."""
        # Create mock arXiv result
        mock_result = Mock()
        mock_result.entry_id = "http://arxiv.org/abs/2301.12345v1"
        mock_result.title = "Deep Learning for NLP"
        mock_result.summary = "A comprehensive study of deep learning in NLP."
        mock_result.authors = [Mock(name="John Doe"), Mock(name="Jane Smith")]
        mock_result.published = datetime(2023, 1, 15)
        mock_result.updated = datetime(2023, 2, 1)
        mock_result.pdf_url = "http://arxiv.org/pdf/2301.12345v1"
        mock_result.primary_category = "cs.CL"
        mock_result.categories = ["cs.CL", "cs.AI"]

        # Mock the arxiv.Client and Search
        mock_client = Mock()
        mock_client.results.return_value = iter([mock_result])

        monkeypatch.setattr("arxiv.Client", Mock(return_value=mock_client))
        monkeypatch.setattr("arxiv.Search", Mock(return_value=Mock()))

        results = arxiv_engine._get_search_results("deep learning")

        assert len(results) == 1
        assert results[0].title == "Deep Learning for NLP"

    def test_search_empty_results(self, arxiv_engine, monkeypatch):
        """Test ArXiv search with no results."""
        mock_client = Mock()
        mock_client.results.return_value = iter([])

        monkeypatch.setattr("arxiv.Client", Mock(return_value=mock_client))
        monkeypatch.setattr("arxiv.Search", Mock(return_value=Mock()))

        results = arxiv_engine._get_search_results("nonexistent query xyz")
        assert results == []


class TestArXivErrorHandling:
    """Tests for ArXiv search error handling."""

    @pytest.fixture(autouse=True)
    def mock_journal_filter(self, monkeypatch):
        """Mock JournalReputationFilter to avoid LLM dependency."""
        monkeypatch.setattr(
            "local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
            Mock(return_value=None),
        )

    @pytest.fixture
    def arxiv_engine(self):
        """Create an ArXiv engine instance."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )

        return ArXivSearchEngine(max_results=10)

    def test_search_handles_network_error(self, arxiv_engine, monkeypatch):
        """Test that network errors are handled gracefully by _get_previews."""
        from urllib.error import URLError

        mock_client = Mock()
        mock_client.results.side_effect = URLError("Network unreachable")

        monkeypatch.setattr("arxiv.Client", Mock(return_value=mock_client))
        monkeypatch.setattr("arxiv.Search", Mock(return_value=Mock()))

        # _get_previews handles exceptions and returns empty list
        results = arxiv_engine._get_previews("test query")
        assert results == []

    def test_search_handles_arxiv_exception(self, arxiv_engine, monkeypatch):
        """Test that arXiv-specific exceptions are handled by _get_previews."""
        import arxiv

        mock_client = Mock()
        mock_client.results.side_effect = arxiv.UnexpectedEmptyPageError(
            "empty", 1, "http://arxiv.org"
        )

        monkeypatch.setattr("arxiv.Client", Mock(return_value=mock_client))
        monkeypatch.setattr("arxiv.Search", Mock(return_value=Mock()))

        # _get_previews handles exceptions and returns empty list
        results = arxiv_engine._get_previews("test query")
        assert results == []


class TestArXivSortingOptions:
    """Tests for ArXiv sorting functionality."""

    @pytest.fixture(autouse=True)
    def mock_journal_filter(self, monkeypatch):
        """Mock JournalReputationFilter to avoid LLM dependency."""
        monkeypatch.setattr(
            "local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
            Mock(return_value=None),
        )

    def test_sort_by_relevance(self):
        """Test sorting by relevance."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )
        import arxiv

        engine = ArXivSearchEngine(sort_by="relevance")
        assert (
            engine.sort_criteria.get(engine.sort_by)
            == arxiv.SortCriterion.Relevance
        )

    def test_sort_by_date(self):
        """Test sorting by submission date."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )
        import arxiv

        engine = ArXivSearchEngine(sort_by="submittedDate")
        assert (
            engine.sort_criteria.get(engine.sort_by)
            == arxiv.SortCriterion.SubmittedDate
        )

    def test_sort_order_ascending(self):
        """Test ascending sort order."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )
        import arxiv

        engine = ArXivSearchEngine(sort_order="ascending")
        assert (
            engine.sort_directions.get(engine.sort_order)
            == arxiv.SortOrder.Ascending
        )


class TestArXivFullTextDownload:
    """Tests for ArXiv full text download functionality."""

    @pytest.fixture(autouse=True)
    def mock_journal_filter(self, monkeypatch):
        """Mock JournalReputationFilter to avoid LLM dependency."""
        monkeypatch.setattr(
            "local_deep_research.advanced_search_system.filters.journal_reputation_filter.JournalReputationFilter.create_default",
            Mock(return_value=None),
        )

    def test_full_text_disabled_by_default(self):
        """Test that full text download is disabled by default."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )

        engine = ArXivSearchEngine()
        assert engine.include_full_text is False

    def test_full_text_enabled_with_download_dir(self):
        """Test that full text can be enabled with download directory."""
        from local_deep_research.web_search_engines.engines.search_engine_arxiv import (
            ArXivSearchEngine,
        )

        engine = ArXivSearchEngine(
            include_full_text=True,
            download_dir="/tmp/arxiv_papers",
            max_full_text=3,
        )

        assert engine.include_full_text is True
        assert engine.download_dir == "/tmp/arxiv_papers"
        assert engine.max_full_text == 3
