"""BibTeX formatting for arXiv papers."""

from __future__ import annotations

import re
import unicodedata

from arxivy.models import Paper


def _normalize_to_ascii(text: str) -> str:
    """Normalize unicode to ASCII for BibTeX keys."""
    normalized = unicodedata.normalize("NFKD", text)
    return normalized.encode("ascii", "ignore").decode("ascii")


def _escape_latex(text: str) -> str:
    """Escape special LaTeX characters in BibTeX field values."""
    if not text:
        return ""
    replacements = [
        ("&", r"\&"),
        ("%", r"\%"),
        ("$", r"\$"),
        ("#", r"\#"),
        ("_", r"\_"),
        ("{", r"\{"),
        ("}", r"\}"),
        ("~", r"\textasciitilde{}"),
        ("^", r"\textasciicircum{}"),
    ]
    result = text
    for old, new in replacements:
        result = result.replace(old, new)
    return result


def _generate_citation_key(paper: Paper) -> str:
    """Generate a citation key: firstauthorlastname + year + firstsignificantword.

    Example: vaswani2017attention
    """
    # First author's last name
    if paper.authors:
        name = paper.authors[0].name
        last_name = name.split()[-1].lower() if name else "unknown"
        last_name = re.sub(r"[^a-z]", "", _normalize_to_ascii(last_name))
    else:
        last_name = "unknown"

    # Year from published date
    year = paper.published[:4] if paper.published and len(paper.published) >= 4 else "nodate"

    # First significant word from title
    if paper.title:
        stopwords = {"a", "an", "the", "on", "in", "of", "for", "and", "or", "to", "with", "is", "are"}
        words = re.findall(r"\b[a-zA-Z]+\b", _normalize_to_ascii(paper.title.lower()))
        title_word = next((w for w in words if w not in stopwords), "paper")
    else:
        title_word = "paper"

    return f"{last_name}{year}{title_word}"


def format_bibtex(paper: Paper) -> str:
    """Convert a single arXiv paper to a BibTeX entry.

    Uses @article if journal_ref is present, @misc otherwise.
    """
    cite_key = _generate_citation_key(paper)
    entry_type = "article" if paper.journal_ref else "misc"

    # Author string: "Name1 and Name2 and Name3"
    if paper.authors:
        author_str = " and ".join(a.name for a in paper.authors if a.name)
    else:
        author_str = ""

    # Year
    year = paper.published[:4] if paper.published and len(paper.published) >= 4 else ""

    # Build fields
    fields = []

    if paper.title:
        fields.append(f"  title = {{{_escape_latex(paper.title)}}}")
    if author_str:
        fields.append(f"  author = {{{_escape_latex(author_str)}}}")
    if year:
        fields.append(f"  year = {{{year}}}")
    if paper.arxiv_id:
        fields.append(f"  eprint = {{{paper.arxiv_id}}}")
        fields.append("  archiveprefix = {arXiv}")
    if paper.primary_category:
        fields.append(f"  primaryclass = {{{paper.primary_category}}}")
    if paper.doi:
        fields.append(f"  doi = {{{paper.doi}}}")
    if paper.journal_ref:
        fields.append(f"  journal = {{{_escape_latex(paper.journal_ref)}}}")
    if paper.summary:
        abstract = paper.summary
        if len(abstract) > 1000:
            abstract = abstract[:997] + "..."
        fields.append(f"  abstract = {{{_escape_latex(abstract)}}}")
    if paper.abstract_url:
        fields.append(f"  url = {{{paper.abstract_url}}}")

    fields_str = ",\n".join(fields)
    return f"@{entry_type}{{{cite_key},\n{fields_str}\n}}"


def format_bibtex_batch(papers: list[Paper]) -> str:
    """Format multiple papers as BibTeX entries, separated by blank lines."""
    entries = [format_bibtex(p) for p in papers if p]
    return "\n\n".join(entries)
