"""Unpaywall API client — open-access PDF URL resolution.

Uses the Unpaywall REST API (https://api.unpaywall.org/v2/{doi})
to find the best open-access PDF URL for a given DOI.
No third-party wrapper needed — direct httpx calls.
"""

from __future__ import annotations

import httpx

__all__ = ["UnpaywallClient", "UnpaywallError"]

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


class UnpaywallError(Exception):
    """Error raised by Unpaywall operations."""


class UnpaywallClient:
    """Unpaywall API client for open-access PDF resolution.

    Args:
        email: Required email for Unpaywall API (polite pool).
    """

    def __init__(self, email: str = "") -> None:
        from axm_bib.config import get_email

        self._email = email or get_email() or ""
        if not self._email:
            msg = (
                "Unpaywall requires a real email address. "
                "Set UNPAYWALL_EMAIL env var or run `axm-bib pdf` interactively."
            )
            raise UnpaywallError(msg)

    def get_pdf_urls(self, doi: str) -> list[str]:
        """Get all open-access PDF URLs for a DOI.

        URLs are sorted by reliability: repositories (arXiv, etc.)
        before publishers (which may 403 on direct download).

        Args:
            doi: Digital Object Identifier.

        Returns:
            List of PDF URLs, empty if not open access.

        Raises:
            UnpaywallError: On network/connection errors.
        """
        url = f"{_UNPAYWALL_BASE}/{doi}"

        try:
            resp = httpx.get(url, params={"email": self._email}, timeout=15.0)
        except Exception as exc:
            msg = f"Unpaywall request failed for DOI '{doi}': {exc}"
            raise UnpaywallError(msg) from exc

        # 404 = DOI not in Unpaywall database → not OA, not an error
        if resp.status_code == 404:
            return []

        # Other errors (422 = bad email, 5xx, etc.) are real problems
        try:
            resp.raise_for_status()
        except httpx.HTTPStatusError as exc:
            msg = f"Unpaywall API error for DOI '{doi}': {resp.status_code}"
            raise UnpaywallError(msg) from exc

        data = resp.json()
        locations = data.get("oa_locations") or []

        # Extract URLs, preferring url_for_pdf over landing page
        repos: list[str] = []
        pubs: list[str] = []
        for loc in locations:
            pdf = loc.get("url_for_pdf") or loc.get("url")
            if not pdf:
                continue
            if loc.get("host_type") == "repository":
                repos.append(pdf)
            else:
                pubs.append(pdf)

        # Repositories first (arXiv etc.) — less likely to 403
        return repos + pubs
