"""
Tests for research_library/downloaders/pubmed.py

Tests cover:
- PubMedDownloader initialization
- can_handle() URL detection
- download() methods
- download_with_result() methods
- PDF download methods
- Text download methods
- Rate limiting
- PMC ID extraction
- Europe PMC API integration
- Error handling
"""

from unittest.mock import MagicMock, patch
import time


class TestPubMedDownloaderInitialization:
    """Tests for PubMedDownloader initialization."""

    def test_default_initialization(self):
        """Test default initialization parameters."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert downloader.timeout == 30
        assert downloader.rate_limit_delay == 1.0
        assert downloader.last_request_time == 0

    def test_custom_timeout(self):
        """Test initialization with custom timeout."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader(timeout=60)

        assert downloader.timeout == 60

    def test_custom_rate_limit(self):
        """Test initialization with custom rate limit."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader(rate_limit_delay=2.0)

        assert downloader.rate_limit_delay == 2.0


class TestCanHandle:
    """Tests for can_handle() URL detection."""

    def test_can_handle_pubmed_url(self):
        """Test PubMed main site URL detection."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert (
            downloader.can_handle("https://pubmed.ncbi.nlm.nih.gov/12345678")
            is True
        )
        assert (
            downloader.can_handle("https://pubmed.ncbi.nlm.nih.gov/12345678/")
            is True
        )

    def test_can_handle_pmc_url(self):
        """Test PMC URL detection."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert (
            downloader.can_handle(
                "https://ncbi.nlm.nih.gov/pmc/articles/PMC1234567"
            )
            is True
        )
        assert (
            downloader.can_handle(
                "https://ncbi.nlm.nih.gov/pmc/articles/PMC1234567/"
            )
            is True
        )

    def test_can_handle_europe_pmc_url(self):
        """Test Europe PMC URL detection."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert (
            downloader.can_handle("https://europepmc.org/article/PMC/1234567")
            is True
        )
        assert (
            downloader.can_handle(
                "https://www.europepmc.org/article/PMC/1234567"
            )
            is True
        )

    def test_cannot_handle_generic_url(self):
        """Test that generic URLs are not handled."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert downloader.can_handle("https://google.com") is False
        assert downloader.can_handle("https://arxiv.org/abs/1234") is False
        assert downloader.can_handle("https://nature.com/article/123") is False

    def test_cannot_handle_empty_url(self):
        """Test that empty URL returns False."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert downloader.can_handle("") is False

    def test_cannot_handle_invalid_url(self):
        """Test that invalid URL returns False."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert downloader.can_handle("not a valid url") is False

    def test_cannot_handle_ncbi_without_pmc(self):
        """Test that NCBI URLs without /pmc are not handled."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        # ncbi.nlm.nih.gov without /pmc should return False
        assert (
            downloader.can_handle("https://ncbi.nlm.nih.gov/gene/12345")
            is False
        )


class TestDownload:
    """Tests for download() method."""

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_apply_rate_limit",
    )
    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_pdf_content",
    )
    def test_download_pdf_success(self, mock_download_pdf, mock_rate_limit):
        """Test successful PDF download."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )
        from local_deep_research.research_library.downloaders.base import (
            ContentType,
        )

        mock_download_pdf.return_value = b"%PDF-1.4 content"

        downloader = PubMedDownloader()
        result = downloader.download(
            "https://pubmed.ncbi.nlm.nih.gov/12345678", ContentType.PDF
        )

        assert result == b"%PDF-1.4 content"
        mock_rate_limit.assert_called_once()

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_apply_rate_limit",
    )
    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_text",
    )
    def test_download_text_success(self, mock_download_text, mock_rate_limit):
        """Test successful text download."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )
        from local_deep_research.research_library.downloaders.base import (
            ContentType,
        )

        mock_download_text.return_value = b"Article text content"

        downloader = PubMedDownloader()
        result = downloader.download(
            "https://pubmed.ncbi.nlm.nih.gov/12345678", ContentType.TEXT
        )

        assert result == b"Article text content"


class TestDownloadWithResult:
    """Tests for download_with_result() method."""

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_apply_rate_limit",
    )
    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_text",
    )
    def test_download_text_with_result_success(
        self, mock_download_text, mock_rate_limit
    ):
        """Test successful text download returns success result."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )
        from local_deep_research.research_library.downloaders.base import (
            ContentType,
        )

        mock_download_text.return_value = b"Article text content"

        downloader = PubMedDownloader()
        result = downloader.download_with_result(
            "https://pubmed.ncbi.nlm.nih.gov/12345678", ContentType.TEXT
        )

        assert result.is_success is True
        assert result.content == b"Article text content"

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_apply_rate_limit",
    )
    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_text",
    )
    def test_download_text_with_result_failure(
        self, mock_download_text, mock_rate_limit
    ):
        """Test failed text download returns skip reason."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )
        from local_deep_research.research_library.downloaders.base import (
            ContentType,
        )

        mock_download_text.return_value = None

        downloader = PubMedDownloader()
        result = downloader.download_with_result(
            "https://pubmed.ncbi.nlm.nih.gov/12345678", ContentType.TEXT
        )

        assert result.is_success is False
        assert "subscription" in result.skip_reason.lower()


class TestApplyRateLimit:
    """Tests for _apply_rate_limit() method."""

    def test_no_delay_on_first_request(self):
        """Test that first request doesn't delay."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader(rate_limit_delay=1.0)
        downloader.last_request_time = 0

        start_time = time.time()
        downloader._apply_rate_limit()
        elapsed = time.time() - start_time

        # Should be nearly instant (no delay)
        assert elapsed < 0.1

    def test_delay_on_rapid_requests(self):
        """Test that rapid requests are rate limited."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader(rate_limit_delay=0.2)

        # First request
        downloader._apply_rate_limit()

        # Second request immediately after
        start_time = time.time()
        downloader._apply_rate_limit()
        elapsed = time.time() - start_time

        # Should have delayed close to rate_limit_delay
        assert elapsed >= 0.15  # Allow some tolerance

    def test_no_delay_after_waiting(self):
        """Test that there's no delay if enough time has passed."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader(rate_limit_delay=0.1)

        # Set last request time to well in the past
        downloader.last_request_time = time.time() - 10

        start_time = time.time()
        downloader._apply_rate_limit()
        elapsed = time.time() - start_time

        # Should be nearly instant
        assert elapsed < 0.05


class TestGetPmcIdFromPmid:
    """Tests for _get_pmc_id_from_pmid() method."""

    @patch("requests.Session.get")
    def test_get_pmc_id_success(self, mock_get):
        """Test successful PMC ID retrieval."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        # Mock NCBI E-utilities response
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "linksets": [{"linksetdbs": [{"dbto": "pmc", "links": [7654321]}]}]
        }
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._get_pmc_id_from_pmid("12345678")

        assert result == "PMC7654321"

    @patch("requests.Session.get")
    def test_get_pmc_id_no_link(self, mock_get):
        """Test when no PMC link exists."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        # Mock response with no PMC links
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"linksets": [{}]}
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._get_pmc_id_from_pmid("12345678")

        assert result is None

    @patch("requests.Session.get")
    def test_get_pmc_id_api_error(self, mock_get):
        """Test PMC ID retrieval when API fails."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_get.side_effect = Exception("Network error")

        downloader = PubMedDownloader()
        result = downloader._get_pmc_id_from_pmid("12345678")

        assert result is None


class TestDownloadViaMethods:
    """Tests for _download_via_* methods."""

    @patch("requests.Session.get")
    def test_download_via_europe_pmc_success(self, mock_get):
        """Test successful download from Europe PMC."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.content = b"%PDF-1.4 Europe PMC content"
        mock_response.headers = {"Content-Type": "application/pdf"}
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._download_via_europe_pmc("PMC1234567")

        assert result == b"%PDF-1.4 Europe PMC content"

    @patch("requests.Session.get")
    def test_download_via_europe_pmc_failure(self, mock_get):
        """Test failed download from Europe PMC."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_response = MagicMock()
        mock_response.status_code = 404
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._download_via_europe_pmc("PMC1234567")

        assert result is None

    @patch("requests.Session.get")
    def test_download_via_ncbi_pmc_success(self, mock_get):
        """Test successful download from NCBI PMC."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.content = b"%PDF-1.4 NCBI PMC content"
        mock_response.headers = {"Content-Type": "application/pdf"}
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._download_via_ncbi_pmc("PMC1234567")

        assert result == b"%PDF-1.4 NCBI PMC content"


class TestDownloadPmcDirect:
    """Tests for _download_pmc_direct() method."""

    def test_extract_pmc_id_from_url(self):
        """Test PMC ID extraction from URL."""
        import re

        url = "https://ncbi.nlm.nih.gov/pmc/articles/PMC7654321"
        pmc_match = re.search(r"(PMC\d+)", url)

        assert pmc_match is not None
        assert pmc_match.group(1) == "PMC7654321"

    def test_pmc_id_not_found(self):
        """Test when PMC ID is not in URL."""
        import re

        url = "https://ncbi.nlm.nih.gov/pmc/articles/"
        pmc_match = re.search(r"(PMC\d+)", url)

        assert pmc_match is None


class TestDownloadPubmed:
    """Tests for _download_pubmed() method."""

    def test_extract_pmid_from_url(self):
        """Test PMID extraction from URL."""
        import re

        url = "https://pubmed.ncbi.nlm.nih.gov/12345678/"
        pmid_match = re.search(r"/(\d+)/?", url)

        assert pmid_match is not None
        assert pmid_match.group(1) == "12345678"

    def test_pmid_not_found(self):
        """Test when PMID is not in URL."""
        import re

        url = "https://pubmed.ncbi.nlm.nih.gov/"
        pmid_match = re.search(r"/(\d+)/?", url)

        assert pmid_match is None


class TestTryEuropePmcApi:
    """Tests for _try_europe_pmc_api() method."""

    @patch("requests.Session.get")
    def test_api_returns_open_access(self, mock_get):
        """Test API returns open access article."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        # First call - API search
        api_response = MagicMock()
        api_response.status_code = 200
        api_response.json.return_value = {
            "resultList": {
                "result": [
                    {
                        "isOpenAccess": "Y",
                        "hasPDF": "Y",
                        "pmcid": "PMC7654321",
                    }
                ]
            }
        }

        # Second call - PDF download
        pdf_response = MagicMock()
        pdf_response.status_code = 200
        pdf_response.content = b"%PDF-1.4 content"
        pdf_response.headers = {"Content-Type": "application/pdf"}

        mock_get.side_effect = [api_response, pdf_response]

        downloader = PubMedDownloader()
        result = downloader._try_europe_pmc_api("12345678")

        assert result == b"%PDF-1.4 content"

    @patch("requests.Session.get")
    def test_api_returns_no_results(self, mock_get):
        """Test API returns no results."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"resultList": {"result": []}}
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._try_europe_pmc_api("12345678")

        assert result is None

    @patch("requests.Session.get")
    def test_api_returns_non_open_access(self, mock_get):
        """Test API returns non-open access article."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "resultList": {
                "result": [
                    {
                        "isOpenAccess": "N",
                        "hasPDF": "N",
                    }
                ]
            }
        }
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._try_europe_pmc_api("12345678")

        assert result is None


class TestDownloadPdfWithResult:
    """Tests for _download_pdf_with_result() method."""

    def test_invalid_pmc_url_format(self):
        """Test invalid PMC URL format returns error result."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()
        downloader._apply_rate_limit = MagicMock()  # Skip rate limiting

        result = downloader._download_pdf_with_result(
            "https://ncbi.nlm.nih.gov/pmc/articles/"
        )

        # Should return skip reason about invalid format
        assert result.is_success is False
        assert result.skip_reason is not None

    def test_invalid_pubmed_url_format(self):
        """Test invalid PubMed URL format returns error result."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()
        downloader._apply_rate_limit = MagicMock()

        result = downloader._download_pdf_with_result(
            "https://pubmed.ncbi.nlm.nih.gov/"
        )

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


class TestFetchTextFromEuropePmc:
    """Tests for _fetch_text_from_europe_pmc() method."""

    @patch("requests.Session.get")
    def test_fetch_text_success(self, mock_get):
        """Test successful text fetch from Europe PMC."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        # First call - metadata
        meta_response = MagicMock()
        meta_response.status_code = 200
        meta_response.json.return_value = {
            "resultList": {
                "result": [
                    {
                        "isOpenAccess": "Y",
                        "pmcid": "PMC7654321",
                    }
                ]
            }
        }

        # Second call - full text XML
        xml_response = MagicMock()
        xml_response.status_code = 200
        xml_response.text = (
            "<article><body><p>Article text content</p></body></article>"
        )

        mock_get.side_effect = [meta_response, xml_response]

        downloader = PubMedDownloader()
        result = downloader._fetch_text_from_europe_pmc("12345678", None)

        assert result is not None
        assert "Article text content" in result

    @patch("requests.Session.get")
    def test_fetch_text_no_open_access(self, mock_get):
        """Test text fetch when article is not open access."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "resultList": {
                "result": [
                    {
                        "isOpenAccess": "N",
                    }
                ]
            }
        }
        mock_get.return_value = mock_response

        downloader = PubMedDownloader()
        result = downloader._fetch_text_from_europe_pmc("12345678", None)

        assert result is None

    def test_fetch_text_no_identifiers(self):
        """Test text fetch with no identifiers."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()
        result = downloader._fetch_text_from_europe_pmc(None, None)

        assert result is None


class TestDownloadText:
    """Tests for _download_text() method."""

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_fetch_text_from_europe_pmc",
    )
    def test_download_text_from_pubmed_url(self, mock_fetch_text):
        """Test text download from PubMed URL."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_fetch_text.return_value = "Full article text"

        downloader = PubMedDownloader()
        result = downloader._download_text(
            "https://pubmed.ncbi.nlm.nih.gov/12345678/"
        )

        assert result == b"Full article text"
        mock_fetch_text.assert_called_once()

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_fetch_text_from_europe_pmc",
    )
    def test_download_text_from_pmc_url(self, mock_fetch_text):
        """Test text download from PMC URL."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_fetch_text.return_value = "PMC article text"

        downloader = PubMedDownloader()
        result = downloader._download_text(
            "https://ncbi.nlm.nih.gov/pmc/articles/PMC7654321/"
        )

        assert result == b"PMC article text"


class TestDownloadPdfContent:
    """Tests for _download_pdf_content() method."""

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_pmc_direct",
    )
    def test_routes_pmc_url_correctly(self, mock_download_pmc):
        """Test that PMC URLs are routed to _download_pmc_direct."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_download_pmc.return_value = b"%PDF-1.4 content"

        downloader = PubMedDownloader()
        result = downloader._download_pdf_content(
            "https://ncbi.nlm.nih.gov/pmc/articles/PMC7654321"
        )

        mock_download_pmc.assert_called_once()
        assert result == b"%PDF-1.4 content"

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_pubmed",
    )
    def test_routes_pubmed_url_correctly(self, mock_download_pubmed):
        """Test that PubMed URLs are routed to _download_pubmed."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_download_pubmed.return_value = b"%PDF-1.4 content"

        downloader = PubMedDownloader()
        result = downloader._download_pdf_content(
            "https://pubmed.ncbi.nlm.nih.gov/12345678"
        )

        mock_download_pubmed.assert_called_once()
        assert result == b"%PDF-1.4 content"

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_europe_pmc",
    )
    def test_routes_europe_pmc_url_correctly(self, mock_download_europe):
        """Test that Europe PMC URLs are routed correctly."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_download_europe.return_value = b"%PDF-1.4 content"

        downloader = PubMedDownloader()
        result = downloader._download_pdf_content(
            "https://europepmc.org/article/PMC/7654321"
        )

        mock_download_europe.assert_called_once()
        assert result == b"%PDF-1.4 content"


class TestDownloadEuropePmc:
    """Tests for _download_europe_pmc() method."""

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_via_europe_pmc",
    )
    def test_extracts_pmc_id_and_downloads(self, mock_download):
        """Test PMC ID extraction and download."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        mock_download.return_value = b"%PDF-1.4 content"

        downloader = PubMedDownloader()
        result = downloader._download_europe_pmc(
            "https://europepmc.org/article/PMC7654321"
        )

        mock_download.assert_called_once_with("PMC7654321")
        assert result == b"%PDF-1.4 content"

    @patch.object(
        __import__(
            "local_deep_research.research_library.downloaders.pubmed",
            fromlist=["PubMedDownloader"],
        ).PubMedDownloader,
        "_download_via_europe_pmc",
    )
    def test_returns_none_when_no_pmc_id(self, mock_download):
        """Test returns None when PMC ID not found."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()
        result = downloader._download_europe_pmc(
            "https://europepmc.org/article/invalid"
        )

        mock_download.assert_not_called()
        assert result is None


class TestEdgeCases:
    """Edge case tests."""

    def test_url_with_query_parameters(self):
        """Test URL with query parameters."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        # Should still handle URLs with query params
        assert (
            downloader.can_handle(
                "https://pubmed.ncbi.nlm.nih.gov/12345678?from=home"
            )
            is True
        )

    def test_url_with_fragment(self):
        """Test URL with fragment."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert (
            downloader.can_handle(
                "https://pubmed.ncbi.nlm.nih.gov/12345678#abstract"
            )
            is True
        )

    def test_http_url(self):
        """Test HTTP (non-HTTPS) URL."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        # Should handle HTTP URLs too
        assert (
            downloader.can_handle("http://pubmed.ncbi.nlm.nih.gov/12345678")
            is True
        )

    def test_url_parsing_exception(self):
        """Test URL that causes parsing exception."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        # Invalid URL should return False without raising
        result = downloader.can_handle("://invalid")
        assert result is False


class TestBaseDownloaderInheritance:
    """Tests for BaseDownloader inheritance."""

    def test_inherits_from_base_downloader(self):
        """Test that PubMedDownloader inherits from BaseDownloader."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )
        from local_deep_research.research_library.downloaders.base import (
            BaseDownloader,
        )

        downloader = PubMedDownloader()

        assert isinstance(downloader, BaseDownloader)

    def test_has_session_attribute(self):
        """Test that downloader has session attribute."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert hasattr(downloader, "session")

    def test_has_download_pdf_method(self):
        """Test that downloader has _download_pdf method from base."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert hasattr(downloader, "_download_pdf")
        assert callable(downloader._download_pdf)

    def test_has_extract_text_from_pdf_method(self):
        """Test that downloader has extract_text_from_pdf method from base."""
        from local_deep_research.research_library.downloaders.pubmed import (
            PubMedDownloader,
        )

        downloader = PubMedDownloader()

        assert hasattr(downloader, "extract_text_from_pdf")
        assert callable(downloader.extract_text_from_pdf)
