"""Tests for huntpdf.resolvers.url."""

from pathlib import Path
from unittest.mock import MagicMock

import pytest
import respx
from httpx import Response

from huntpdf.errors import PDFNotFound
from huntpdf.resolvers.url import resolve_url


class TestResolveUrl:
    @respx.mock
    def test_arxiv_abs_url(self, monkeypatch, tmp_path):
        respx.head("https://arxiv.org/abs/2301.07041").mock(
            return_value=Response(200, headers={"content-type": "text/html"})
        )
        expected = tmp_path / "paper.pdf"
        mock_arxiv = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.resolve_arxiv", mock_arxiv)

        result = resolve_url("https://arxiv.org/abs/2301.07041", expected)
        assert result == expected
        mock_arxiv.assert_called_once_with("2301.07041", expected)

    @respx.mock
    def test_arxiv_pdf_url(self, monkeypatch, tmp_path):
        respx.head("https://arxiv.org/pdf/2301.07041").mock(
            return_value=Response(200, headers={"content-type": "application/pdf"})
        )
        expected = tmp_path / "paper.pdf"
        mock_arxiv = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.resolve_arxiv", mock_arxiv)

        result = resolve_url("https://arxiv.org/pdf/2301.07041", expected)
        assert result == expected
        mock_arxiv.assert_called_once_with("2301.07041", expected)

    @respx.mock
    def test_doi_url(self, monkeypatch, tmp_path):
        respx.head("https://doi.org/10.1038/s41586-020-2649-2").mock(
            return_value=Response(200, headers={"content-type": "text/html"})
        )
        expected = tmp_path / "paper.pdf"
        mock_doi = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.resolve_doi", mock_doi)

        result = resolve_url(
            "https://doi.org/10.1038/s41586-020-2649-2", expected
        )
        assert result == expected
        mock_doi.assert_called_once_with("10.1038/s41586-020-2649-2", expected)

    @respx.mock
    def test_pubmed_url(self, monkeypatch, tmp_path):
        respx.head("https://pubmed.ncbi.nlm.nih.gov/12345678").mock(
            return_value=Response(200, headers={"content-type": "text/html"})
        )
        expected = tmp_path / "paper.pdf"
        mock_pubmed = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.resolve_pubmed", mock_pubmed)

        result = resolve_url(
            "https://pubmed.ncbi.nlm.nih.gov/12345678", expected
        )
        assert result == expected
        mock_pubmed.assert_called_once_with("12345678", expected)

    @respx.mock
    def test_pmc_url(self, monkeypatch, tmp_path):
        respx.head("https://pmc.ncbi.nlm.nih.gov/articles/PMC7654321").mock(
            return_value=Response(200, headers={"content-type": "text/html"})
        )
        expected = tmp_path / "paper.pdf"
        mock_pmc = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.resolve_pmc", mock_pmc)

        result = resolve_url(
            "https://pmc.ncbi.nlm.nih.gov/articles/PMC7654321", expected
        )
        assert result == expected
        mock_pmc.assert_called_once_with("PMC7654321", expected)

    @respx.mock
    def test_direct_pdf_url(self, monkeypatch, tmp_path):
        respx.head("https://example.com/files/report.pdf").mock(
            return_value=Response(
                200, headers={"content-type": "application/pdf"}
            )
        )
        expected = tmp_path / "report.pdf"
        mock_download = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.download_pdf", mock_download)

        result = resolve_url("https://example.com/files/report.pdf", expected)
        assert result == expected
        mock_download.assert_called_once_with(
            "https://example.com/files/report.pdf", expected
        )

    @respx.mock
    def test_redirect_to_known_pattern(self, monkeypatch, tmp_path):
        respx.head("https://short.link/abc").mock(
            return_value=Response(
                200,
                headers={
                    "content-type": "text/html",
                },
                extensions={"redirect_url": "https://arxiv.org/abs/2301.07041"},
            )
        )
        expected = tmp_path / "paper.pdf"
        mock_arxiv = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.resolvers.url.resolve_arxiv", mock_arxiv)

        # respx doesn't easily simulate redirects via url change,
        # so we mock httpx.head directly
        mock_head_response = MagicMock()
        mock_head_response.url = "https://arxiv.org/abs/2301.07041"
        mock_head_response.headers = {"content-type": "text/html"}
        monkeypatch.setattr(
            "huntpdf.resolvers.url.httpx.head", lambda *a, **kw: mock_head_response
        )

        result = resolve_url("https://short.link/abc", expected)
        assert result == expected
        mock_arxiv.assert_called_once_with("2301.07041", expected)

    @respx.mock
    def test_unknown_url_falls_back_to_browser(self, monkeypatch, tmp_path):
        respx.head("https://example.com/some-page").mock(
            return_value=Response(200, headers={"content-type": "text/html"})
        )
        expected = tmp_path / "download.pdf"
        mock_browser = MagicMock(return_value=expected)
        monkeypatch.setattr(
            "huntpdf.resolvers.url.fetch_pdf_browser_sync", mock_browser
        )

        result = resolve_url("https://example.com/some-page", expected)
        assert result == expected
        mock_browser.assert_called_once()

    @respx.mock
    def test_browser_fallback_fails_raises_not_found(self, monkeypatch):
        respx.head("https://example.com/nothing").mock(
            return_value=Response(200, headers={"content-type": "text/html"})
        )
        monkeypatch.setattr(
            "huntpdf.resolvers.url.fetch_pdf_browser_sync",
            MagicMock(side_effect=Exception("browser failed")),
        )
        with pytest.raises(PDFNotFound, match="Could not find a PDF"):
            resolve_url("https://example.com/nothing")
