"""Resolve DOIs to PDF files via Unpaywall, with Semantic Scholar fallback."""

import os
from pathlib import Path

import httpx

from huntpdf.download import download_pdf
from huntpdf.errors import DownloadFailed, PDFNotFound

_UNPAYWALL_BASE = "https://api.unpaywall.org/v2"


def resolve_doi(doi: str, output: Path | None = None) -> Path:
    """Download the PDF for a DOI using Unpaywall, falling back to Semantic Scholar.

    Args:
        doi: A DOI string (e.g. "10.1038/s41586-020-2649-2").
        output: Optional destination path. Defaults to current directory.

    Returns:
        Path to the downloaded PDF.

    Raises:
        PDFNotFound: If no open-access PDF is available from any source.
    """
    email = os.environ.get("UNPAYWALL_EMAIL")
    if not email:
        raise PDFNotFound(
            "UNPAYWALL_EMAIL environment variable is required for DOI lookups. "
            "Set it to your email address: export UNPAYWALL_EMAIL=you@example.com"
        )

    if output is None:
        safe_doi = doi.replace("/", "_")
        output = Path.cwd() / f"{safe_doi}.pdf"

    pdf_url = _try_unpaywall(doi, email)

    if pdf_url:
        try:
            return download_pdf(pdf_url, output)
        except (DownloadFailed, PDFNotFound):
            pass

    # Unpaywall URL failed or wasn't available — try Semantic Scholar
    return _try_semantic_scholar(doi, output)


def _try_unpaywall(doi: str, email: str) -> str | None:
    """Query Unpaywall for an open-access PDF URL. Returns None on any failure."""
    url = f"{_UNPAYWALL_BASE}/{doi}?email={email}"
    try:
        response = httpx.get(url, timeout=30.0)
        if response.status_code == 404:
            return None
        response.raise_for_status()
    except httpx.HTTPError:
        return None

    data = response.json()
    best = data.get("best_oa_location") or {}
    return best.get("url_for_pdf")


def _try_semantic_scholar(doi: str, output: Path) -> Path:
    """Use Semantic Scholar to find an open-access copy via alternate identifiers."""
    from huntpdf.scholar import lookup_doi

    result = lookup_doi(doi)
    if result is None or not result.has_alternatives:
        raise PDFNotFound(
            f"No open-access PDF found for DOI: {doi}. "
            "The article may be behind a paywall."
        )

    # Prefer existing resolvers for known IDs — they produce direct PDF URLs
    if result.arxiv_id:
        try:
            from huntpdf.resolvers.arxiv import resolve_arxiv
            return resolve_arxiv(result.arxiv_id, output)
        except Exception:
            pass

    if result.pmcid:
        try:
            from huntpdf.resolvers.pmc import resolve_pmc
            return resolve_pmc(result.pmcid, output)
        except Exception:
            pass

    # Last resort: try the S2 open-access URL directly
    if result.open_access_url:
        try:
            return download_pdf(result.open_access_url, output)
        except Exception:
            pass

    raise PDFNotFound(
        f"No open-access PDF found for DOI: {doi}. "
        "The article may be behind a paywall."
    )
