"""Pure command implementations for the CLI.

Typer command functions should stay thin wrappers around these helpers so the
core behavior remains easy to unit-test and reuse.
"""

from __future__ import annotations

from collections.abc import Callable

from arxivy.api.client import ArxivClient
from arxivy.api.types import SortBy, SortOrder
from arxivy.models import Paper, PaperListResult

ClientFactory = Callable[[], ArxivClient]


def run_search(
    *,
    query: str,
    limit: int,
    offset: int,
    category: str | None,
    sort_by: SortBy | str | None,
    sort_order: SortOrder | str | None,
    client_factory: ClientFactory | None = None,
) -> PaperListResult:
    if client_factory is None:
        client_factory = ArxivClient

    with client_factory() as api:
        return api.search(
            query=query,
            limit=limit,
            offset=offset,
            category=category,
            sort_by=sort_by,
            sort_order=sort_order,
        )


def run_paper(*, ids: list[str], client_factory: ClientFactory | None = None) -> Paper | list[Paper]:
    if client_factory is None:
        client_factory = ArxivClient

    with client_factory() as api:
        if len(ids) == 1:
            return api.get_paper(ids[0])
        return api.get_papers(ids)


def run_bibtex(*, ids: list[str], client_factory: ClientFactory | None = None) -> Paper | list[Paper]:
    """Fetch papers for BibTeX export.

    The CLI decides how to render the returned object.
    """
    return run_paper(ids=ids, client_factory=client_factory)


def run_new(*, category: str, limit: int, client_factory: ClientFactory | None = None) -> PaperListResult:
    if client_factory is None:
        client_factory = ArxivClient

    with client_factory() as api:
        return api.get_new(category=category, limit=limit)
