#!/usr/bin/env python3
"""
Search the OpenAlex Works API. No API key required -- set the OPENALEX_MAILTO
environment variable to an email address to use OpenAlex's "polite pool" for
higher and more reliable rate limits (OpenAlex's own recommendation, not a
credential). Coverage is broader than Crossref alone (includes arXiv, IEEE,
and most publishers' metadata in one place) and each result carries an
open-access PDF link when one exists.

CLI usage:
    python3 search_openalex.py "UAV magnetic compensation" --max 10

Importable:
    from search_openalex import search_openalex
"""
import sys
import os
import json
import argparse
import urllib.parse

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from http_utils import fetch

OPENALEX_API = "https://api.openalex.org/works"
SELECT_FIELDS = ",".join([
    "doi", "title", "display_name", "publication_year", "authorships",
    "primary_location", "open_access", "cited_by_count", "abstract_inverted_index",
])


def _reconstruct_abstract(inverted_index):
    """OpenAlex returns abstracts as a word -> [positions] inverted index
    (for copyright reasons) instead of plain text; rebuild the plain text."""
    if not inverted_index:
        return None
    positions = {}
    for word, idxs in inverted_index.items():
        for i in idxs:
            positions[i] = word
    if not positions:
        return None
    return " ".join(positions[i] for i in sorted(positions))


def search_openalex(query, max_results=10, timeout=20):
    params = {"search": query, "per_page": max_results, "select": SELECT_FIELDS}
    mailto = os.environ.get("OPENALEX_MAILTO")
    if mailto:
        params["mailto"] = mailto
    url = f"{OPENALEX_API}?{urllib.parse.urlencode(params)}"
    data = json.loads(fetch(url, timeout=timeout))
    results = []
    for item in data.get("results", []) or []:
        title = item.get("title") or item.get("display_name")
        authors = [
            a.get("author", {}).get("display_name")
            for a in (item.get("authorships") or [])
            if a.get("author")
        ]
        doi = item.get("doi")
        if doi and doi.startswith("https://doi.org/"):
            doi = doi[len("https://doi.org/"):]
        primary_location = item.get("primary_location") or {}
        source = primary_location.get("source") or {}
        open_access = item.get("open_access") or {}
        results.append({
            "source": "openalex",
            "title": title,
            "authors": authors,
            "year": item.get("publication_year"),
            "venue": source.get("display_name"),
            "doi": doi,
            "arxiv_id": None,
            "abstract": _reconstruct_abstract(item.get("abstract_inverted_index")),
            "citation_count": item.get("cited_by_count"),
            "pdf_url": open_access.get("oa_url") or primary_location.get("pdf_url"),
        })
    return results


if __name__ == "__main__":
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("query")
    ap.add_argument("--max", type=int, default=10)
    args = ap.parse_args()
    try:
        out = search_openalex(args.query, args.max)
        print(json.dumps(out, ensure_ascii=False, indent=2))
    except Exception as e:
        print(json.dumps({"error": str(e)}, ensure_ascii=False))
        sys.exit(1)
