"""Resolve arbitrary URLs to PDF files."""

import re
from pathlib import Path
from urllib.parse import urlparse

import httpx

from huntpdf.browser import fetch_pdf_browser_sync
from huntpdf.download import download_pdf
from huntpdf.errors import PDFNotFound
from huntpdf.resolvers.arxiv import resolve_arxiv
from huntpdf.resolvers.doi import resolve_doi
from huntpdf.resolvers.pmc import resolve_pmc
from huntpdf.resolvers.pubmed import resolve_pubmed

_USER_AGENT = "huntpdf/0.1.0"

_ARXIV_ABS_RE = re.compile(r"arxiv\.org/abs/(.+?)(?:\?|$)")
_ARXIV_PDF_RE = re.compile(r"arxiv\.org/pdf/(.+?)(?:\.pdf)?(?:\?|$)")
_DOI_RE = re.compile(r"doi\.org/(10\..+)$")
_PUBMED_RE = re.compile(r"pubmed\.ncbi\.nlm\.nih\.gov/(\d+)")
_PMC_RE = re.compile(r"pmc\.ncbi\.nlm\.nih\.gov/articles/(PMC\d+)", re.IGNORECASE)


def _extract_known_pattern(url: str, output: Path | None) -> Path | None:
    """Try to match a URL against known academic site patterns."""
    for pattern, handler in [
        (_ARXIV_ABS_RE, lambda m: resolve_arxiv(m.group(1), output)),
        (_ARXIV_PDF_RE, lambda m: resolve_arxiv(m.group(1), output)),
        (_DOI_RE, lambda m: resolve_doi(m.group(1), output)),
        (_PUBMED_RE, lambda m: resolve_pubmed(m.group(1), output)),
        (_PMC_RE, lambda m: resolve_pmc(m.group(1), output)),
    ]:
        match = pattern.search(url)
        if match:
            return handler(match)
    return None


def _default_filename(url: str) -> str:
    """Derive a filename from the URL path."""
    parsed = urlparse(url)
    segments = [s for s in parsed.path.rstrip("/").split("/") if s]
    if segments:
        name = segments[-1]
        if not name.endswith(".pdf"):
            name += ".pdf"
        return name
    return "download.pdf"


def resolve_url(url: str, output: Path | None = None) -> Path:
    """Download a PDF from a URL, detecting known academic site patterns.

    Args:
        url: Any HTTP(S) URL.
        output: Optional destination path. Defaults to current directory.

    Returns:
        Path to the downloaded PDF.

    Raises:
        PDFNotFound: If no PDF can be obtained from the URL.
    """
    headers = {"User-Agent": _USER_AGENT}
    head_response = None

    try:
        head_response = httpx.head(
            url, headers=headers, follow_redirects=True, timeout=30.0
        )
        final_url = str(head_response.url)
    except httpx.HTTPError:
        final_url = url

    for candidate in (url, final_url):
        result = _extract_known_pattern(candidate, output)
        if result is not None:
            return result

    content_type = (
        head_response.headers.get("content-type", "")
        if head_response is not None
        else ""
    )
    if "application/pdf" in content_type:
        if output is None:
            output = Path.cwd() / _default_filename(final_url)
        return download_pdf(final_url, output)

    if output is None:
        output = Path.cwd() / _default_filename(final_url)

    try:
        return fetch_pdf_browser_sync(final_url, output)
    except Exception as exc:
        raise PDFNotFound(
            f"Could not find a PDF at: {url}"
        ) from exc
