"""
Click CLI commands for the proxy file system.
"""

import json
from pathlib import Path

import click

from markitect.proxy.exceptions import ProxyError


@click.group("proxy")
def proxy_group():
    """Proxy file operations — create, update, and manage markdown proxies."""
    pass


@proxy_group.command("create")
@click.argument("source", type=click.Path(exists=True))
@click.option(
    "--output-dir", "-o",
    type=click.Path(),
    default=".",
    help="Directory to write the proxy file (default: current dir).",
)
@click.option("--force", "-f", is_flag=True, help="Overwrite existing proxy file.")
def proxy_create(source, output_dir, force):
    """Create a markdown proxy for SOURCE."""
    # Lazy imports so the CLI group registers even if deps are absent
    from markitect.proxy.registry import registry
    import markitect.proxy.extractors  # noqa: F401  — registers built-ins
    from markitect.proxy.generator import ProxyGenerator

    gen = ProxyGenerator(registry)
    try:
        proxy_path = gen.create(Path(source), Path(output_dir), force=force)
        click.echo(f"Created proxy: {proxy_path}")
    except ProxyError as exc:
        click.echo(f"Error: {exc}", err=True)
        raise SystemExit(1)


@proxy_group.command("update")
@click.argument("target", type=click.Path(exists=True))
@click.option("--dry-run", is_flag=True, help="Show what would change without writing.")
def proxy_update(target, dry_run):
    """Re-extract a single proxy file or all proxies in a directory."""
    from markitect.proxy.registry import registry
    import markitect.proxy.extractors  # noqa: F401
    from markitect.proxy.generator import ProxyGenerator

    gen = ProxyGenerator(registry)
    target_path = Path(target).resolve()

    try:
        if target_path.is_file():
            _update_one(gen, target_path, dry_run)
        elif target_path.is_dir():
            proxies = _find_proxy_files(gen, target_path)
            if not proxies:
                click.echo("No proxy files found.")
                return
            for p in proxies:
                _update_one(gen, p, dry_run)
        else:
            click.echo(f"Error: {target} is not a file or directory.", err=True)
            raise SystemExit(1)
    except ProxyError as exc:
        click.echo(f"Error: {exc}", err=True)
        raise SystemExit(1)


@proxy_group.command("status")
@click.argument("directory", type=click.Path(exists=True), default=".")
@click.option(
    "--format", "output_format",
    type=click.Choice(["table", "json"]),
    default="table",
    help="Output format.",
)
def proxy_status(directory, output_format):
    """Show freshness of all proxy files in DIRECTORY (default: current dir)."""
    from markitect.proxy.registry import registry
    import markitect.proxy.extractors  # noqa: F401
    from markitect.proxy.generator import ProxyGenerator

    gen = ProxyGenerator(registry)

    try:
        results = gen.bulk_status(Path(directory))
    except ProxyError as exc:
        click.echo(f"Error: {exc}", err=True)
        raise SystemExit(1)

    if not results:
        click.echo("No proxy files found.")
        return

    if output_format == "json":
        click.echo(json.dumps(results, indent=2))
    else:
        _print_status_table(results)


@proxy_group.command("extractors")
@click.option(
    "--format", "output_format",
    type=click.Choice(["table", "json"]),
    default="table",
    help="Output format.",
)
def proxy_extractors(output_format):
    """List registered extractors and their dependency status."""
    from markitect.proxy.registry import registry
    import markitect.proxy.extractors  # noqa: F401

    extractors = registry.list_extractors()

    if output_format == "json":
        rows = [
            {
                "name": e.name,
                "version": e.version,
                "extensions": list(e.extensions),
                "installed": e.check_dependencies(),
                "hint": e.dependency_hint(),
            }
            for e in extractors
        ]
        click.echo(json.dumps(rows, indent=2))
    else:
        _print_extractor_table(extractors)


# ------------------------------------------------------------------
# helpers
# ------------------------------------------------------------------

def _update_one(gen, proxy_path, dry_run):
    """Update a single proxy file, respecting --dry-run."""
    info = gen.status(proxy_path)
    if info["status"] == "current":
        click.echo(f"  {proxy_path.name}: current")
        return
    if info["status"] == "missing-source":
        click.echo(f"  {proxy_path.name}: source missing")
        return
    if dry_run:
        click.echo(f"  {proxy_path.name}: stale (would update)")
    else:
        updated = gen.update(proxy_path)
        label = "updated" if updated else "current"
        click.echo(f"  {proxy_path.name}: {label}")


def _find_proxy_files(gen, directory):
    """Return proxy file paths within *directory*."""
    results = []
    for path in sorted(directory.rglob("*.md")):
        meta, _ = gen._try_read_proxy(path)
        if meta is not None and meta.get("proxy") is True:
            results.append(path)
    return results


def _print_status_table(results):
    """Pretty-print a status table."""
    click.echo(f"{'Proxy':<40} {'Source':<30} {'Status':<15} {'Extractor':<10}")
    click.echo("-" * 95)
    for r in results:
        proxy_name = Path(r["proxy"]).name
        click.echo(
            f"{proxy_name:<40} {r['source']:<30} {r['status']:<15} {r['extractor']:<10}"
        )


def _print_extractor_table(extractors):
    """Pretty-print an extractor table."""
    click.echo(f"{'Name':<15} {'Version':<10} {'Extensions':<25} {'Status':<10}")
    click.echo("-" * 60)
    for e in extractors:
        exts = ", ".join(e.extensions)
        status = "installed" if e.check_dependencies() else "missing"
        click.echo(f"{e.name:<15} {e.version:<10} {exts:<25} {status:<10}")
