"""
Integration tests for download_content tool in MCP strategy.
"""

from unittest.mock import MagicMock, patch

from local_deep_research.content_fetcher import ContentFetcher
from local_deep_research.research_library.downloaders.base import DownloadResult


class TestMCPDownloadContentTool:
    """Test download_content tool integration with MCP strategy."""

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_execute_download_content_success(self, mock_get_downloader):
        """Test successful content download via MCP strategy executor."""
        # Setup mock
        mock_downloader = MagicMock()
        mock_downloader.download_with_result.return_value = DownloadResult(
            content=b"# Research Paper\n\nThis is the abstract of the paper discussing important findings.",
            is_success=True,
        )
        mock_downloader.get_metadata.return_value = {
            "title": "Important Research Paper",
            "author": "Dr. Smith",
        }
        mock_get_downloader.return_value = mock_downloader

        # Import and test the executor pattern
        from local_deep_research.content_fetcher import ContentFetcher

        fetcher = ContentFetcher()
        result = fetcher.fetch(
            "https://arxiv.org/abs/2301.12345",
            max_length=5000,
        )

        assert result["status"] == "success"
        assert "abstract" in result["content"].lower()
        assert result["source_type"] == "arXiv"

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_execute_download_content_with_truncation(
        self, mock_get_downloader
    ):
        """Test content truncation for very long papers."""
        # Create a very long paper content
        long_content = "Introduction. " * 5000  # ~70k characters

        mock_downloader = MagicMock()
        mock_downloader.download_with_result.return_value = DownloadResult(
            content=long_content.encode("utf-8"),
            is_success=True,
        )
        mock_downloader.get_metadata.return_value = {}
        mock_get_downloader.return_value = mock_downloader

        fetcher = ContentFetcher()
        result = fetcher.fetch(
            "https://arxiv.org/abs/2301.12345",
            max_length=1000,
        )

        assert result["status"] == "success"
        assert len(result["content"]) < 2000  # Should be truncated
        assert "truncated" in result["content"].lower()

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_execute_download_content_paper_not_found(
        self, mock_get_downloader
    ):
        """Test handling when paper is not available."""
        mock_downloader = MagicMock()
        mock_downloader.download_with_result.return_value = DownloadResult(
            content=None,
            is_success=False,
            skip_reason="Paper not found or requires subscription",
        )
        mock_get_downloader.return_value = mock_downloader

        fetcher = ContentFetcher()
        result = fetcher.fetch("https://example.com/paywalled-paper")

        assert result["status"] == "error"
        assert (
            "subscription" in result["error"].lower()
            or "not found" in result["error"].lower()
        )

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    @patch(
        "local_deep_research.content_fetcher.fetcher.policy_aware_validate_url",
        return_value=True,
    )
    def test_execute_download_content_timeout(
        self, mock_validate, mock_get_downloader
    ):
        """Test handling of timeout during download."""
        mock_downloader = MagicMock()
        mock_downloader.download_with_result.side_effect = TimeoutError(
            "Connection timed out"
        )
        mock_get_downloader.return_value = mock_downloader

        fetcher = ContentFetcher()
        result = fetcher.fetch("https://slow-server.example.com/paper")

        assert result["status"] == "error"
        assert (
            "timed out" in result["error"].lower()
            or "timeout" in result["error"].lower()
        )


class TestDownloadContentWithRealURLPatterns:
    """Test with real-world URL patterns."""

    def test_arxiv_url_variants(self):
        """Test various arXiv URL formats are recognized."""
        fetcher = ContentFetcher()

        # Standard abstract
        info = fetcher.get_url_info("https://arxiv.org/abs/2301.12345")
        assert info["url_type"] == "arxiv"
        assert info["extracted_id"] == "2301.12345"

        # With version
        info = fetcher.get_url_info("https://arxiv.org/abs/2301.12345v3")
        assert info["url_type"] == "arxiv"
        assert info["extracted_id"] == "2301.12345v3"

        # PDF link
        info = fetcher.get_url_info("https://arxiv.org/pdf/2301.12345.pdf")
        assert info["url_type"] == "arxiv"

        # HTML version
        info = fetcher.get_url_info("https://arxiv.org/html/2301.12345")
        assert info["url_type"] == "arxiv"

        # ar5iv (HTML rendering)
        info = fetcher.get_url_info("https://ar5iv.org/abs/2301.12345")
        assert info["url_type"] == "arxiv"

        # Old format (pre-2007)
        info = fetcher.get_url_info("https://arxiv.org/abs/hep-th/9901001")
        assert info["url_type"] == "arxiv"

    def test_pubmed_url_variants(self):
        """Test various PubMed URL formats."""
        fetcher = ContentFetcher()

        # Standard PubMed
        info = fetcher.get_url_info("https://pubmed.ncbi.nlm.nih.gov/12345678")
        assert info["url_type"] == "pubmed"
        assert info["extracted_id"] == "12345678"

        # With trailing slash
        info = fetcher.get_url_info("https://pubmed.ncbi.nlm.nih.gov/12345678/")
        assert info["url_type"] == "pubmed"

        # Old format
        info = fetcher.get_url_info(
            "https://www.ncbi.nlm.nih.gov/pubmed/12345678"
        )
        assert info["url_type"] == "pubmed"

    def test_pmc_url_variants(self):
        """Test various PMC URL formats."""
        fetcher = ContentFetcher()

        # Standard PMC
        info = fetcher.get_url_info(
            "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1234567/"
        )
        assert info["url_type"] == "pmc"
        assert info["extracted_id"] == "PMC1234567"

        # Europe PMC
        info = fetcher.get_url_info("https://europepmc.org/article/PMC/1234567")
        assert info["url_type"] == "pmc"

    def test_semantic_scholar_url_variants(self):
        """Test Semantic Scholar URL formats."""
        fetcher = ContentFetcher()

        # With paper title in URL
        info = fetcher.get_url_info(
            "https://www.semanticscholar.org/paper/Attention-Is-All-You-Need-Vaswani-Shazeer/abcdef1234567890abcdef1234567890abcdef12"
        )
        assert info["url_type"] == "semantic_scholar"

        # API URL
        info = fetcher.get_url_info(
            "https://api.semanticscholar.org/v1/paper/abcd1234"
        )
        assert info["url_type"] == "semantic_scholar"

    def test_biorxiv_medrxiv_url_variants(self):
        """Test bioRxiv and medRxiv URL formats."""
        fetcher = ContentFetcher()

        # bioRxiv
        info = fetcher.get_url_info(
            "https://www.biorxiv.org/content/10.1101/2021.01.01.123456v1"
        )
        assert info["url_type"] == "biorxiv"

        # medRxiv
        info = fetcher.get_url_info(
            "https://www.medrxiv.org/content/10.1101/2021.01.01.123456v1"
        )
        assert info["url_type"] == "medrxiv"

    def test_doi_url_variants(self):
        """Test DOI URL formats."""
        fetcher = ContentFetcher()

        # doi.org
        info = fetcher.get_url_info("https://doi.org/10.1038/nature12373")
        assert info["url_type"] == "doi"
        assert "10.1038" in info["extracted_id"]

        # dx.doi.org
        info = fetcher.get_url_info(
            "https://dx.doi.org/10.1126/science.1234567"
        )
        assert info["url_type"] == "doi"


class TestDownloadContentEdgeCases:
    """Test edge cases and error handling."""

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_empty_url(self, mock_get_downloader):
        """Test handling of empty URL."""
        fetcher = ContentFetcher()
        # Empty URL should still try to classify and fetch
        info = fetcher.get_url_info("")
        assert info["url_type"] == "html"  # Falls back to HTML

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_malformed_url(self, mock_get_downloader):
        """Test handling of malformed URL."""
        mock_downloader = MagicMock()
        mock_downloader.download_with_result.side_effect = ValueError(
            "Invalid URL"
        )
        mock_get_downloader.return_value = mock_downloader

        fetcher = ContentFetcher()
        result = fetcher.fetch("not-a-valid-url")

        assert result["status"] == "error"

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_binary_pdf_content(self, mock_get_downloader):
        """Test handling of binary PDF content that can't be decoded as UTF-8."""
        # Simulate PDF bytes that fail UTF-8 decoding
        pdf_bytes = b"%PDF-1.4\x00\x01\x02\x03binary content"

        mock_downloader = MagicMock()
        mock_downloader.download_with_result.return_value = DownloadResult(
            content=pdf_bytes,
            is_success=True,
        )
        mock_downloader.get_metadata.return_value = {}
        mock_get_downloader.return_value = mock_downloader

        # Mock the PDF text extraction to return extracted text
        with patch(
            "local_deep_research.research_library.downloaders.base.BaseDownloader.extract_text_from_pdf"
        ) as mock_extract:
            mock_extract.return_value = "Extracted PDF text content"

            fetcher = ContentFetcher()
            result = fetcher.fetch("https://example.com/paper.pdf")

            # Should attempt PDF extraction
            assert result["status"] == "success" or result["status"] == "error"

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_rate_limited_response(self, mock_get_downloader):
        """Test handling of rate-limited responses."""
        mock_downloader = MagicMock()
        mock_downloader.download_with_result.return_value = DownloadResult(
            content=None,
            is_success=False,
            skip_reason="Rate limited - too many requests (429)",
        )
        mock_get_downloader.return_value = mock_downloader

        fetcher = ContentFetcher()
        result = fetcher.fetch("https://arxiv.org/abs/2301.12345")

        assert result["status"] == "error"
        assert "rate" in result["error"].lower() or "429" in result["error"]

    @patch(
        "local_deep_research.content_fetcher.fetcher.ContentFetcher._get_downloader"
    )
    def test_subscription_required(self, mock_get_downloader):
        """Test handling of paywalled content."""
        mock_downloader = MagicMock()
        mock_downloader.download_with_result.return_value = DownloadResult(
            content=None,
            is_success=False,
            skip_reason="Subscription required to access full text",
        )
        mock_get_downloader.return_value = mock_downloader

        fetcher = ContentFetcher()
        result = fetcher.fetch("https://nature.com/articles/paywalled")

        assert result["status"] == "error"
        assert "subscription" in result["error"].lower()


class TestDownloadContentCaching:
    """Test downloader caching behavior."""

    def test_downloader_reuse(self):
        """Test that downloaders are cached and reused."""
        fetcher = ContentFetcher()

        # Get HTML downloader twice
        d1 = fetcher._get_downloader(
            __import__(
                "local_deep_research.content_fetcher.url_classifier",
                fromlist=["URLType"],
            ).URLType.HTML
        )
        d2 = fetcher._get_downloader(
            __import__(
                "local_deep_research.content_fetcher.url_classifier",
                fromlist=["URLType"],
            ).URLType.HTML
        )

        # Should be the same instance
        assert d1 is d2

    def test_different_downloaders_for_different_types(self):
        """Test that different URL types get different downloaders."""
        from local_deep_research.content_fetcher.url_classifier import URLType

        fetcher = ContentFetcher()

        html_downloader = fetcher._get_downloader(URLType.HTML)
        # Other downloaders may not be available, but HTML should always work
        assert html_downloader is not None
