from __future__ import annotations

from typing import List, Optional

from ..types import Candidate
from .base import BaseProvider


BASE_URL = "https://api.semanticscholar.org/graph/v1"
FIELDS = "title,year,authors,venue,externalIds,url"


class SemanticScholarProvider(BaseProvider):
    provider_name = "semanticscholar"
    min_delay_seconds = 1.1
    timeout_seconds = 10.0
    max_results = 5

    def __init__(self, *args, api_key: Optional[str] = None, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.api_key = api_key

    def lookup_by_id(self, identifier: str, id_type: str) -> List[Candidate]:
        if id_type == "doi":
            paper_id = f"DOI:{identifier}"
        elif id_type == "arxiv":
            paper_id = f"ARXIV:{identifier}"
        else:
            return []
        url = f"{BASE_URL}/paper/{paper_id}"
        payload = self._request_json(url, params={"fields": FIELDS}, headers=self._headers())
        if payload["status_code"] != 200:
            return []
        data = payload["data"]
        candidate = _candidate_from_paper(data)
        return [candidate] if candidate else []

    def search(self, query: str) -> List[Candidate]:
        url = f"{BASE_URL}/paper/search"
        params = {"query": query, "limit": self.max_results, "fields": FIELDS}
        payload = self._request_json(url, params=params, headers=self._headers())
        if payload["status_code"] != 200:
            return []
        data = payload["data"] or {}
        results = data.get("data", [])
        candidates = []
        for item in results:
            candidate = _candidate_from_paper(item)
            if candidate:
                candidates.append(candidate)
        return candidates

    def _headers(self) -> dict:
        headers = {}
        if self.api_key:
            headers["x-api-key"] = self.api_key
        return headers


def _candidate_from_paper(data: dict) -> Optional[Candidate]:
    if not data:
        return None
    authors = [author.get("name") for author in data.get("authors", []) if author.get("name")]
    external_ids = data.get("externalIds") or {}
    ids = {}
    for key, value in external_ids.items():
        if not value:
            continue
        key_lower = key.lower()
        if key_lower in {"doi", "arxiv", "isbn"}:
            ids[key_lower] = value
    return Candidate(
        provider="semanticscholar",
        provider_id=data.get("paperId") or data.get("paper_id") or "",
        title=data.get("title"),
        authors=authors,
        year=data.get("year"),
        venue=data.get("venue"),
        ids=ids,
        url=data.get("url"),
        evidence={"source": "paper"},
    )
