"""Tests for Semantic Scholar PDF downloader."""

from unittest.mock import Mock, patch


from local_deep_research.research_library.downloaders.semantic_scholar import (
    SemanticScholarDownloader,
)


class TestSemanticScholarDownloaderInit:
    """Tests for SemanticScholarDownloader initialization."""

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

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

    def test_initializes_with_api_key(self):
        """Should accept optional API key."""
        downloader = SemanticScholarDownloader(api_key="test-key")
        assert downloader.api_key == "test-key"

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


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

    def test_handles_semantic_scholar_url(self):
        """Should handle semanticscholar.org URLs."""
        downloader = SemanticScholarDownloader()
        assert downloader.can_handle(
            "https://www.semanticscholar.org/paper/abc123"
        )
        assert downloader.can_handle("https://semanticscholar.org/paper/abc123")

    def test_rejects_other_urls(self):
        """Should reject non-semantic-scholar URLs."""
        downloader = SemanticScholarDownloader()
        assert not downloader.can_handle("https://arxiv.org/abs/1234.5678")
        assert not downloader.can_handle("https://example.com/paper.pdf")

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


class TestSemanticScholarDownloaderExtractPaperId:
    """Tests for _extract_paper_id method."""

    def test_returns_none_for_invalid_url(self):
        """Should return None for invalid URLs."""
        downloader = SemanticScholarDownloader()
        paper_id = downloader._extract_paper_id("https://example.com/paper")
        assert paper_id is None


class TestSemanticScholarDownloaderGetPdfUrl:
    """Tests for _get_pdf_url method."""

    def test_returns_none_for_api_error(self):
        """Should return None when API returns error."""
        downloader = SemanticScholarDownloader()

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

        with patch.object(
            downloader.session, "get", return_value=mock_response
        ):
            pdf_url = downloader._get_pdf_url("abc123")

        assert pdf_url is None

    def test_handles_rate_limiting(self):
        """Should handle rate limiting (429) gracefully."""
        downloader = SemanticScholarDownloader()

        mock_response = Mock()
        mock_response.status_code = 429
        mock_response.raise_for_status = Mock(
            side_effect=Exception("Rate limited")
        )

        with patch.object(
            downloader.session, "get", return_value=mock_response
        ):
            pdf_url = downloader._get_pdf_url("abc123")

        assert pdf_url is None


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

    def test_handles_no_pdf_available(self):
        """Should handle case when no PDF is available."""
        downloader = SemanticScholarDownloader()

        with patch.object(downloader, "_get_pdf_url", return_value=None):
            result = downloader.download(
                "https://www.semanticscholar.org/paper/abc123"
            )

        assert result is None


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

    def test_returns_skip_reason_when_no_pdf(self):
        """Should return skip_reason when no PDF available."""
        downloader = SemanticScholarDownloader()

        with patch.object(downloader, "_get_pdf_url", return_value=None):
            result = downloader.download_with_result(
                "https://www.semanticscholar.org/paper/abc123"
            )

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