# paper_search_mcp/paper.py
from dataclasses import dataclass
from datetime import datetime
from typing import List, Dict, Optional

@dataclass
class Paper:
    """Standardized paper format with core fields for academic sources"""
    # 核心字段（必填，但允许空值或默认值）
    paper_id: str              # Unique identifier (e.g., arXiv ID, PMID, DOI)
    title: str                 # Paper title
    authors: List[str]         # List of author names
    abstract: str              # Abstract text
    doi: str                   # Digital Object Identifier
    published_date: datetime   # Publication date
    pdf_url: str               # Direct PDF link
    url: str                   # URL to paper page
    source: str                # Source platform (e.g., 'arxiv', 'pubmed')

    # 可选字段
    updated_date: Optional[datetime] = None    # Last updated date
    journal: str = ""                          # Journal/venue name
    categories: List[str] = None               # Subject categories
    keywords: List[str] = None                 # Keywords
    citations: int = 0                         # Citation count
    references: Optional[List[str]] = None     # List of reference IDs/DOIs
    extra: Optional[Dict] = None               # Source-specific extra metadata
    year_only: bool = False                    # True when only year is known (no month/day)

    def __post_init__(self):
        """Post-initialization to handle default values"""
        if self.authors is None:
            self.authors = []
        if self.categories is None:
            self.categories = []
        if self.keywords is None:
            self.keywords = []
        if self.references is None:
            self.references = []
        if self.extra is None:
            self.extra = {}

    def to_dict(self, abstract_limit: int = 200) -> Dict:
        """Convert paper to dictionary format for serialization.

        Args:
            abstract_limit: Max chars for abstract. 0 = omit, -1 = full (default: 200)
        """
        # Process abstract based on limit
        if abstract_limit == 0:
            abstract = None
        elif abstract_limit > 0 and self.abstract and len(self.abstract) > abstract_limit:
            abstract = self.abstract[:abstract_limit] + '...'
        else:
            abstract = self.abstract

        # Date handling: year-only vs full date
        if self.published_date and self.published_date != datetime.min:
            if self.year_only:
                date_str = str(self.published_date.year)
            else:
                date_str = self.published_date.strftime('%Y-%m-%d')
        else:
            date_str = None

        result = {
            'id': self.paper_id,
            'source': self.source or None,
            'title': self.title,
            'authors': self.authors if self.authors else None,
            'abstract': abstract,
            'date': date_str,
            'doi': self.doi or None,
            'url': self.url or None,
            'pdf': self.pdf_url or None,
            'journal': self.journal or None,
            'categories': self.categories if self.categories else None,
            'keywords': self.keywords if self.keywords else None,
            'citations': self.citations if self.citations else None,
            'extra': self.extra if self.extra else None,
        }

        # Remove None/empty values
        return {k: v for k, v in result.items() if v is not None and v != ''}