"""axm-bib CLI — standalone bibliographic tools.

Usage::

    axm-bib search "loop invariants"
    axm-bib doi 10.1145/363235.363259
    axm-bib pdf 10.1145/363235.363259
    axm-bib extract paper.pdf
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import Annotated

import cyclopts

from axm_bib.config import resolve_email
from axm_bib.pipeline import BibPipeline

__all__ = ["app", "doi", "extract", "pdf", "search"]

app = cyclopts.App(
    name="axm-bib",
    help="Bibliographic tools: search papers, resolve DOIs to BibTeX, download PDFs.",
)


@app.command()
def search(
    query: Annotated[
        str,
        cyclopts.Parameter(help="Search query (title, keywords)"),
    ],
    *,
    limit: Annotated[
        int,
        cyclopts.Parameter(
            name=["--limit", "-n"],
            help="Maximum results (default: 5, max: 100)",
        ),
    ] = 5,
    abstract: Annotated[
        bool,
        cyclopts.Parameter(
            name=["--abstract/--no-abstract"],
            help="Show paper abstracts in results",
        ),
    ] = True,
    abstract_len: Annotated[
        int,
        cyclopts.Parameter(
            name=["--abstract-len"],
            help="Truncate abstracts to N chars (0 = full)",
        ),
    ] = 0,
) -> None:
    """Search papers by title or keywords (-n: max results, default 5, max 100)."""
    if not query.strip():
        print("Error: query must not be empty", file=sys.stderr)
        raise SystemExit(1)

    if limit < 1:
        print(f"Error: limit must be ≥ 1, got {limit}", file=sys.stderr)
        raise SystemExit(1)
    limit = min(limit, 100)

    try:
        pipeline = BibPipeline()
        papers = pipeline.search(query, limit=limit)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        raise SystemExit(1) from None

    if not papers:
        print("No results found.")
        return

    for i, p in enumerate(papers, 1):
        authors = ", ".join(p.authors[:3])
        if len(p.authors) > 3:
            authors += " et al."
        print(f"[{i}] {p.title}")
        print(f"    Authors: {authors}")
        id_str = p.doi or (f"arXiv:{p.arxiv_id}" if p.arxiv_id else "N/A")
        print(f"    Year: {p.year or '?'}  DOI: {id_str}")
        if abstract and p.abstract:
            snippet = p.abstract
            if abstract_len > 0 and len(snippet) > abstract_len:
                snippet = snippet[:abstract_len] + "..."
            print(f"    {snippet}")
        print()


@app.command()
def doi(
    doi_str: Annotated[
        str,
        cyclopts.Parameter(help="Digital Object Identifier"),
    ],
) -> None:
    """Resolve a DOI to BibTeX (via CrossRef)."""
    if not doi_str.strip():
        print("Error: DOI must not be empty", file=sys.stderr)
        raise SystemExit(1)

    try:
        pipeline = BibPipeline()
        entry = pipeline.resolve_bibtex(doi_str)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        raise SystemExit(1) from None

    print(entry.raw)


@app.command()
def pdf(
    doi_str: Annotated[
        str,
        cyclopts.Parameter(help="Digital Object Identifier"),
    ],
    *,
    output_dir: Annotated[
        Path | None,
        cyclopts.Parameter(
            name=["--output-dir", "-o"],
            help="Download directory",
        ),
    ] = None,
) -> None:
    """Download open-access PDF for a DOI (via Unpaywall + arXiv fallback)."""
    if not doi_str.strip():
        print("Error: DOI must not be empty", file=sys.stderr)
        raise SystemExit(1)

    try:
        email = resolve_email()
        pipeline = BibPipeline(mailto=email)
        result = pipeline.download_pdf(doi_str)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        raise SystemExit(1) from None

    if result is None:
        print("Paper is not open access — no PDF available.")
        return

    print(f"Downloaded: {result.paper_dir or result.path}")
    print(f"  PDF: {Path(result.path).name} ({result.size_bytes:,} bytes)")
    if result.bibtex_path:
        print(f"  BibTeX: {Path(result.bibtex_path).name}")
    if result.extraction:
        ext = result.extraction
        print(
            f"  Markdown: {Path(ext.markdown_path).name}"
            f" ({ext.char_count:,} chars, {ext.page_count} pages)"
        )
        print(f"  Figures: {len(ext.figures)}")


@app.command()
def extract(
    pdf_path: Annotated[
        Path,
        cyclopts.Parameter(help="Path to PDF file"),
    ],
    *,
    output_dir: Annotated[
        Path | None,
        cyclopts.Parameter(
            name=["--output-dir", "-o"],
            help="Output directory (default: {stem}/ next to PDF)",
        ),
    ] = None,
    figures: Annotated[
        bool,
        cyclopts.Parameter(
            name=["--figures/--no-figures"],
            help="Extract figures as PNG",
        ),
    ] = True,
) -> None:
    """Extract PDF to Markdown + figures (PNG)."""
    if not pdf_path.exists():
        print(f"Error: file not found: {pdf_path}", file=sys.stderr)
        raise SystemExit(1)

    try:
        from axm_bib.extract import extract_pdf

        result = extract_pdf(pdf_path, output_dir)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        raise SystemExit(1) from None

    print(f"Extracted: {result.output_dir}")
    print(f"  Markdown: {result.markdown_path} ({result.char_count:,} chars)")
    print(f"  Pages: {result.page_count}")
    print(f"  Figures: {len(result.figures)}")
    for fig in result.figures:
        print(f"    {fig.filename} (p.{fig.page + 1}, {fig.width}x{fig.height})")


if __name__ == "__main__":
    app()
