"""fetch_arxiv — Search and retrieve arXiv papers via the official arXiv API.

No API key required. Uses the `arxiv` PyPI package (lukasschwab/arxiv.py).
Rate limit: 3 requests/second — well within any agent use pattern.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any


def fetch_arxiv(
    query: str | None = None,
    paper_id: str | None = None,
    max_results: int = 5,
    download_pdf: bool = False,
    output_path: str = "./papers/",
) -> dict[str, Any]:
    """Search arXiv by query or fetch a specific paper by ID.

    Args:
        query: Search query string. Use this OR paper_id.
        paper_id: arXiv paper ID (e.g. '1706.03762'). Use this OR query.
        max_results: Maximum results for query search (default 5, max 50).
        download_pdf: If True, download PDFs to output_path.
        output_path: Directory for downloaded PDFs (default './papers/').

    Returns:
        dict with keys:
            - papers: list of paper dicts (title, authors, abstract, arxiv_id,
                      url, pdf_url, published, categories)
            - count: number of papers returned
            - downloaded: list of local file paths (if download_pdf=True)
            - error: error message string (if something went wrong)
    """
    try:
        import arxiv  # type: ignore[import]
    except ImportError:
        return {
            "error": (
                "The 'arxiv' package is required for fetch_arxiv. "
                "Install it with: pip install arxiv"
            ),
            "papers": [],
            "count": 0,
            "downloaded": [],
        }

    if not query and not paper_id:
        return {
            "error": "Either 'query' or 'paper_id' must be provided.",
            "papers": [],
            "count": 0,
            "downloaded": [],
        }

    if query and paper_id:
        return {
            "error": "Provide either 'query' or 'paper_id', not both.",
            "papers": [],
            "count": 0,
            "downloaded": [],
        }

    max_results = min(max(1, max_results), 50)

    try:
        client = arxiv.Client()

        if paper_id:
            # Fetch specific paper by ID — normalize common formats
            pid = paper_id.strip()
            # Strip any leading 'arXiv:' prefix
            if pid.lower().startswith("arxiv:"):
                pid = pid[6:]
            search = arxiv.Search(id_list=[pid])
        else:
            search = arxiv.Search(
                query=query,
                max_results=max_results,
                sort_by=arxiv.SortCriterion.Relevance,
            )

        results = list(client.results(search))

        papers = []
        for result in results:
            papers.append({
                "arxiv_id": result.entry_id.split("/abs/")[-1],
                "title": result.title,
                "authors": [str(a) for a in result.authors],
                "abstract": result.summary.strip(),
                "published": result.published.isoformat() if result.published else None,
                "updated": result.updated.isoformat() if result.updated else None,
                "url": result.entry_id,
                "pdf_url": result.pdf_url,
                "categories": result.categories,
                "doi": result.doi,
                "journal_ref": result.journal_ref,
            })

        downloaded: list[str] = []
        if download_pdf and papers:
            out_dir = Path(output_path)
            out_dir.mkdir(parents=True, exist_ok=True)
            for i, (result, paper) in enumerate(zip(results, papers)):
                safe_id = paper["arxiv_id"].replace("/", "_").replace(".", "_")
                filename = f"{safe_id}.pdf"
                dest = out_dir / filename
                try:
                    result.download_pdf(dirpath=str(out_dir), filename=filename)
                    downloaded.append(str(dest))
                except Exception as e:
                    downloaded.append(f"ERROR downloading {paper['arxiv_id']}: {e}")

        return {
            "papers": papers,
            "count": len(papers),
            "downloaded": downloaded,
            "query": query,
            "paper_id": paper_id,
        }

    except Exception as e:
        return {
            "error": f"arXiv API error: {e}",
            "papers": [],
            "count": 0,
            "downloaded": [],
        }


async def handler(params: dict) -> dict:
    """Skill entry point — delegates to fetch_arxiv()."""
    return fetch_arxiv(**params)
