"""Tests for BioRxiv PDF downloader."""

from unittest.mock import Mock, patch


from local_deep_research.research_library.downloaders.biorxiv import (
    BioRxivDownloader,
)


class TestBioRxivDownloaderInit:
    """Tests for BioRxivDownloader initialization."""

    def test_initializes_with_default_timeout(self):
        """Should initialize with default timeout."""
        downloader = BioRxivDownloader()
        assert downloader.timeout == 30

    def test_initializes_with_custom_timeout(self):
        """Should accept custom timeout."""
        downloader = BioRxivDownloader(timeout=60)
        assert downloader.timeout == 60

    def test_creates_session(self):
        """Should create a requests session."""
        downloader = BioRxivDownloader()
        assert downloader.session is not None


class TestBioRxivDownloaderCanHandle:
    """Tests for can_handle method."""

    def test_handles_biorxiv_url(self):
        """Should handle biorxiv.org URLs."""
        downloader = BioRxivDownloader()
        assert downloader.can_handle(
            "https://www.biorxiv.org/content/10.1101/2024.01.01"
        )
        assert downloader.can_handle(
            "https://biorxiv.org/content/10.1101/2024.01.01"
        )

    def test_handles_medrxiv_url(self):
        """Should handle medrxiv.org URLs."""
        downloader = BioRxivDownloader()
        assert downloader.can_handle(
            "https://www.medrxiv.org/content/10.1101/2024.01.01"
        )
        assert downloader.can_handle(
            "https://medrxiv.org/content/10.1101/2024.01.01"
        )

    def test_rejects_other_urls(self):
        """Should reject non-biorxiv URLs."""
        downloader = BioRxivDownloader()
        assert not downloader.can_handle("https://arxiv.org/abs/1234.5678")
        assert not downloader.can_handle(
            "https://pubmed.ncbi.nlm.nih.gov/12345"
        )
        assert not downloader.can_handle("https://example.com/paper.pdf")

    def test_rejects_empty_url(self):
        """Should reject empty URLs."""
        downloader = BioRxivDownloader()
        assert not downloader.can_handle("")

    def test_rejects_none_url(self):
        """Should handle None URL gracefully."""
        downloader = BioRxivDownloader()
        # Should not raise, just return False
        try:
            result = downloader.can_handle(None)
            assert result is False
        except (TypeError, AttributeError):
            # Acceptable to raise for None
            pass


class TestBioRxivDownloaderConvertToPdfUrl:
    """Tests for _convert_to_pdf_url method."""

    def test_converts_content_url_to_pdf_url(self):
        """Should convert content URL to PDF URL."""
        downloader = BioRxivDownloader()
        url = "https://www.biorxiv.org/content/10.1101/2024.01.15.575123v1"
        pdf_url = downloader._convert_to_pdf_url(url)
        assert pdf_url is not None
        assert ".pdf" in pdf_url

    def test_handles_medrxiv_url(self):
        """Should handle medrxiv URLs."""
        downloader = BioRxivDownloader()
        url = "https://www.medrxiv.org/content/10.1101/2024.02.20.12345678v2"
        pdf_url = downloader._convert_to_pdf_url(url)
        assert pdf_url is not None

    def test_handles_non_biorxiv_url(self):
        """Should handle non-biorxiv URL (may return URL or None)."""
        downloader = BioRxivDownloader()
        # The method may return a URL or None for non-biorxiv URLs
        downloader._convert_to_pdf_url("https://example.com/paper")
        # Just verify it doesn't raise - behavior varies


class TestBioRxivDownloaderDownload:
    """Tests for download method."""

    def test_downloads_pdf_successfully(self, mock_pdf_content):
        """Should download PDF successfully."""
        downloader = BioRxivDownloader()

        # Mock the session
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.content = mock_pdf_content
        mock_response.raise_for_status = Mock()

        with patch.object(
            downloader.session, "get", return_value=mock_response
        ):
            with patch.object(
                downloader, "_download_pdf", return_value=mock_pdf_content
            ):
                downloader.download(
                    "https://www.biorxiv.org/content/10.1101/2024.01.15.575123v1"
                )

        # Result depends on implementation - just verify it doesn't raise

    def test_handles_download_failure(self):
        """Should handle download failure gracefully."""
        downloader = BioRxivDownloader()

        with patch.object(
            downloader.session, "get", side_effect=Exception("Network error")
        ):
            result = downloader.download(
                "https://www.biorxiv.org/content/10.1101/2024.01.15.575123v1"
            )

        assert result is None

    def test_handles_404_response(self):
        """Should handle 404 response."""
        downloader = BioRxivDownloader()

        mock_response = Mock()
        mock_response.status_code = 404
        mock_response.raise_for_status = Mock(
            side_effect=Exception("404 Not Found")
        )

        with patch.object(
            downloader.session, "get", return_value=mock_response
        ):
            result = downloader.download(
                "https://www.biorxiv.org/content/10.1101/2024.01.15.575123v1"
            )

        assert result is None


class TestBioRxivDownloaderDownloadWithResult:
    """Tests for download_with_result method."""

    def test_returns_download_result_structure(self, mock_pdf_content):
        """Should return DownloadResult with expected structure."""
        downloader = BioRxivDownloader()

        # The actual download behavior depends on network/mocking
        # Just verify the method returns a proper DownloadResult
        result = downloader.download_with_result(
            "https://www.biorxiv.org/content/10.1101/test"
        )

        # Should return a DownloadResult (success or failure)
        assert hasattr(result, "is_success")
        assert hasattr(result, "content")
        assert hasattr(result, "skip_reason")

    def test_returns_skip_reason_on_failure(self):
        """Should return skip_reason when download fails."""
        downloader = BioRxivDownloader()

        with patch.object(downloader, "_convert_to_pdf_url", return_value=None):
            result = downloader.download_with_result(
                "https://example.com/invalid"
            )

        assert result.is_success is False
        assert result.skip_reason is not None


class TestBioRxivDownloaderFetchAbstract:
    """Tests for _fetch_abstract_from_page method."""

    def test_fetches_abstract_from_page(self):
        """Should fetch abstract from page HTML."""
        downloader = BioRxivDownloader()

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.text = """
            <html>
            <body>
                <div class="abstract">
                    <p>This is the abstract content.</p>
                </div>
            </body>
            </html>
        """
        mock_response.raise_for_status = Mock()

        with patch.object(
            downloader.session, "get", return_value=mock_response
        ):
            downloader._fetch_abstract_from_page(
                "https://www.biorxiv.org/content/10.1101/test"
            )

        # Should return something (may be None if parsing fails)
        # The exact result depends on the HTML structure expected by the method

    def test_handles_fetch_failure(self):
        """Should handle fetch failure gracefully."""
        downloader = BioRxivDownloader()

        with patch.object(
            downloader.session, "get", side_effect=Exception("Network error")
        ):
            abstract = downloader._fetch_abstract_from_page(
                "https://www.biorxiv.org/content/10.1101/test"
            )

        assert abstract is None
