"""Core data models for arxivy.

This module intentionally contains no network/parsing logic.
"""

from __future__ import annotations

from dataclasses import asdict, dataclass, field
from typing import Any


@dataclass
class Author:
    """An arXiv paper author."""

    name: str = ""
    affiliation: str = ""


@dataclass
class Paper:
    """A parsed arXiv paper entry."""

    arxiv_id: str = ""
    title: str = ""
    summary: str = ""
    authors: list[Author] = field(default_factory=list)
    published: str = ""
    updated: str = ""
    categories: list[str] = field(default_factory=list)
    primary_category: str = ""
    comment: str = ""
    journal_ref: str = ""
    doi: str = ""
    pdf_url: str = ""
    abstract_url: str = ""

    def to_dict(self) -> dict[str, Any]:
        return asdict(self)


@dataclass
class PaperListResult:
    """A list of papers along with optional metadata."""

    results: list[Paper]

    # Keep this optional so we can omit it from JSON when empty.
    #
    # NOTE: dict is supported for backwards compatibility, but new code should
    # prefer PaperListMeta for type safety.
    meta: PaperListMeta | dict[str, Any] | None = None

    def to_dict(self) -> dict[str, Any]:
        output: dict[str, Any] = {"results": [asdict(p) for p in self.results]}
        if isinstance(self.meta, PaperListMeta):
            output["meta"] = self.meta.to_dict()
        elif self.meta:
            output["meta"] = self.meta
        return output


@dataclass
class PaperListMeta:
    """Metadata returned by arXiv's feed endpoints."""

    total_results: int = 0
    start_index: int = 0
    items_per_page: int = 0
    query: str | None = None
    category: str | None = None

    def is_empty(self) -> bool:
        return (
            self.total_results == 0
            and self.start_index == 0
            and self.items_per_page == 0
            and self.query is None
            and self.category is None
        )

    def to_dict(self) -> dict[str, Any]:
        output: dict[str, Any] = {
            "total_results": self.total_results,
            "start_index": self.start_index,
            "items_per_page": self.items_per_page,
        }
        if self.query is not None:
            output["query"] = self.query
        if self.category is not None:
            output["category"] = self.category
        return output
