"""CLI interface using Typer."""
from __future__ import annotations

import re
import sys
from pathlib import Path

try:
    import typer
except ImportError:
    typer = None


def _save_figures(input_path: Path, output_dir: Path, figures, markdown: str) -> str:
    """Save figure images and rewrite markdown image references.

    For raster figures (xref set): extracts image bytes from the PDF.
    For vector figures (image_data set): saves the pre-rendered PNG bytes.

    Returns the updated markdown with rewritten image paths.
    """
    import fitz

    figures_dir = output_dir / "figures"
    figures_dir.mkdir(parents=True, exist_ok=True)

    doc = fitz.open(str(input_path))
    try:
        for fig in figures:
            # Determine the filename pattern used in markdown
            fig_num = fig.image_index + 1
            page_num = fig.page_num + 1
            original_ref = f"figure_{page_num}_{fig_num}.png"
            # Use markdown link syntax for replacement to avoid matching
            # substrings in already-rewritten paths (e.g. "figures/figure_1_1.png"
            # contains "figure_1_1.png")
            old_link = f"]({original_ref})"

            if fig.image_data:
                # Pre-rendered figure (vector or composite cluster): already have PNG bytes
                save_path = figures_dir / original_ref
                save_path.write_bytes(fig.image_data)
                new_ref = str(save_path.relative_to(output_dir))
                markdown = markdown.replace(old_link, f"]({new_ref})")
            elif fig.xref is not None:
                # Raster figure: extract image bytes from PDF
                try:
                    img_data = doc.extract_image(fig.xref)
                    if img_data and img_data.get("image"):
                        ext = img_data.get("ext", "png")
                        save_name = f"figure_{page_num}_{fig_num}.{ext}"
                        save_path = figures_dir / save_name
                        save_path.write_bytes(img_data["image"])
                        new_ref = str(save_path.relative_to(output_dir))
                        markdown = markdown.replace(old_link, f"]({new_ref})")
                except Exception:
                    pass  # skip figures that can't be extracted
    finally:
        doc.close()

    return markdown


def main():
    """Convert a research paper PDF to Markdown."""
    if len(sys.argv) < 2:
        print("Usage: paper2md <input.pdf> [output.md]")
        sys.exit(1)

    input_path = Path(sys.argv[1])
    output_path = Path(sys.argv[2]) if len(sys.argv) > 2 else input_path.with_suffix(".md")

    if not input_path.exists():
        print(f"Error: {input_path} not found")
        sys.exit(1)

    from .core import convert
    from .types import PipelineConfig

    def progress_cb(stage: str, current: int, total: int) -> None:
        print(f"\r{stage}: {current}/{total}    ", end="", flush=True)

    config = PipelineConfig(progress_callback=progress_cb)
    print(f"Converting {input_path}...")

    result = convert(input_path, config)
    print()  # newline after progress

    output_path.write_text(result.markdown, encoding="utf-8")
    print(f"Output: {output_path}")
    print(f"Title: {result.title}")
    print(f"Pages: {result.page_count}")
    print(f"Tables: {len(result.tables)}")
    print(f"Figures: {len(result.figures)}")
    print(f"References: {len(result.references)}")

    if result.warnings:
        for w in result.warnings:
            print(f"Warning: {w}")


if typer is not None:
    app = typer.Typer(help="paper2md: PDF to Markdown for research papers")

    @app.command()
    def convert_cmd(
        input_path: Path = typer.Argument(..., help="Path to input PDF"),
        output: Path = typer.Option(None, "--output", "-o", help="Output Markdown path"),
        output_dir: Path = typer.Option(None, "--output-dir", "-d", help="Output directory (saves .md + figures/)"),
        no_tables: bool = typer.Option(False, "--no-tables", help="Skip table extraction"),
        no_figures: bool = typer.Option(False, "--no-figures", help="Skip figure extraction"),
        no_equations: bool = typer.Option(False, "--no-equations", help="Skip equation extraction"),
        no_references: bool = typer.Option(False, "--no-references", help="Skip reference extraction"),
    ):
        """Convert a research paper PDF to Markdown."""
        if not input_path.exists():
            typer.echo(f"Error: {input_path} not found")
            raise typer.Exit(1)

        # Determine output path
        if output_dir is not None:
            output_dir = Path(output_dir)
            output_dir.mkdir(parents=True, exist_ok=True)
            output_path = output_dir / "paper.md"
        elif output is not None:
            output_path = output
        else:
            output_path = input_path.with_suffix(".md")

        from .core import convert
        from .types import PipelineConfig

        def progress_cb(stage: str, current: int, total: int) -> None:
            typer.echo(f"\r{stage}: {current}/{total}    ", nl=False)

        config = PipelineConfig(
            extract_tables=not no_tables,
            extract_figures=not no_figures,
            extract_equations=not no_equations,
            extract_references=not no_references,
            progress_callback=progress_cb,
        )

        typer.echo(f"Converting {input_path}...")
        result = convert(input_path, config)
        typer.echo()  # newline after progress

        markdown = result.markdown

        # Save figures and rewrite image paths when --output-dir is used
        if output_dir is not None and result.figures:
            markdown = _save_figures(input_path, output_dir, result.figures, markdown)

        output_path.write_text(markdown, encoding="utf-8")
        typer.echo(f"Output: {output_path}")
        typer.echo(f"Title: {result.title}")
        typer.echo(f"Pages: {result.page_count}")
        typer.echo(f"Tables: {len(result.tables)}")
        typer.echo(f"Figures: {len(result.figures)}")
        typer.echo(f"References: {len(result.references)}")

        if output_dir is not None and result.figures:
            figures_dir = output_dir / "figures"
            saved = len(list(figures_dir.glob("*"))) if figures_dir.exists() else 0
            typer.echo(f"Figures saved: {saved} in {figures_dir}")
else:
    app = None
