from __future__ import annotations

from typing import List

from ..types import Candidate
from .base import BaseProvider


BASE_URL = "https://openlibrary.org"


class OpenLibraryProvider(BaseProvider):
    provider_name = "openlibrary"
    min_delay_seconds = 0.5
    timeout_seconds = 10.0
    max_results = 5

    def lookup_by_id(self, identifier: str, id_type: str) -> List[Candidate]:
        if id_type != "isbn":
            return []
        url = f"{BASE_URL}/isbn/{identifier}.json"
        payload = self._request_json(url)
        if payload["status_code"] != 200:
            return []
        data = payload["data"]
        candidate = _candidate_from_isbn(data)
        return [candidate] if candidate else []

    def search(self, query: str) -> List[Candidate]:
        url = f"{BASE_URL}/search.json"
        params = {"q": query, "limit": self.max_results}
        payload = self._request_json(url, params=params)
        if payload["status_code"] != 200:
            return []
        docs = payload["data"].get("docs", [])
        candidates = []
        for doc in docs:
            candidates.append(_candidate_from_search(doc))
        return [candidate for candidate in candidates if candidate]


def _candidate_from_isbn(data: dict) -> Candidate | None:
    if not data:
        return None
    year = _extract_year(data.get("publish_date"))
    isbn = (data.get("isbn_13") or [None])[0] or (data.get("isbn_10") or [None])[0]
    ids = {"isbn": isbn} if isbn else {}
    return Candidate(
        provider="openlibrary",
        provider_id=data.get("key", ""),
        title=data.get("title"),
        authors=_extract_author_names(data.get("authors")),
        year=year,
        venue=data.get("publishers")[0] if data.get("publishers") else None,
        ids=ids,
        url=f"{BASE_URL}{data.get('key', '')}" if data.get("key") else None,
        evidence={"source": "isbn"},
    )


def _candidate_from_search(doc: dict) -> Candidate | None:
    if not doc:
        return None
    authors = doc.get("author_name") or []
    year = doc.get("first_publish_year")
    isbn = (doc.get("isbn") or [None])[0]
    ids = {"isbn": isbn} if isbn else {}
    return Candidate(
        provider="openlibrary",
        provider_id=doc.get("key") or "",
        title=doc.get("title"),
        authors=authors,
        year=int(year) if isinstance(year, int) else None,
        venue=None,
        ids=ids,
        url=f"{BASE_URL}{doc.get('key', '')}" if doc.get("key") else None,
        evidence={"source": "search"},
    )


def _extract_author_names(authors_field) -> list[str]:
    if not authors_field:
        return []
    names = []
    for author in authors_field:
        if isinstance(author, dict) and author.get("name"):
            names.append(author["name"])
    return names


def _extract_year(value) -> int | None:
    if value is None:
        return None
    if isinstance(value, int):
        return value
    text = str(value)
    digits = "".join(ch for ch in text if ch.isdigit())
    if len(digits) >= 4:
        return int(digits[:4])
    return None
