"""defuddle wrapper for AKP ingest pipelines.

Wraps the `defuddle` CLI (npm package, ~7.6K★) to strip web junk
(nav/ads/footer/scripts) and return clean Markdown + structured metadata.

Why: AKP ingest scripts feed raw HTML into LLMs (or store it raw in the
brain) which wastes 30-50% of tokens on chrome. defuddle is by Obsidian's
CEO and is the production extractor behind the Obsidian Clipper.

Usage:
    from aria_lib.defuddle_clean import clean_html, clean_url

    out = clean_url("https://example.com/article")
    out["markdown"]    # clean MD
    out["title"]       # article title
    out["author"]      # detected author or ""
    out["word_count"]  # estimate
    out["raw"]         # full defuddle JSON

Falls back to returning the input on any subprocess error so callers don't
crash; check `out["ok"]` for success.

Requires `defuddle` on PATH. `npm install -g defuddle`.
"""
from __future__ import annotations

import json
import subprocess
import tempfile
from pathlib import Path

# Reasonable default — defuddle parses ~20-200ms typically; allow 10s for slow URLs.
DEFAULT_TIMEOUT = 10


def _run_defuddle(source: str, timeout: int = DEFAULT_TIMEOUT) -> dict:
    """Run `defuddle parse <source> --json` and return parsed dict.

    `source` can be a URL or a path to a local HTML file. Caller controls
    which.
    """
    try:
        proc = subprocess.run(
            ["defuddle", "parse", source, "--json"],
            capture_output=True,
            text=True,
            timeout=timeout,
            check=False,
        )
    except FileNotFoundError as e:
        return {"ok": False, "error": f"defuddle not installed: {e}"}
    except subprocess.TimeoutExpired:
        return {"ok": False, "error": f"defuddle timeout after {timeout}s"}

    if proc.returncode != 0:
        return {"ok": False, "error": f"defuddle exit {proc.returncode}: {proc.stderr.strip()[:200]}"}

    try:
        data = json.loads(proc.stdout)
    except json.JSONDecodeError as e:
        return {"ok": False, "error": f"defuddle bad json: {e}"}

    return {
        "ok": True,
        "markdown": data.get("contentMarkdown", "").strip(),
        "title": data.get("title", "").strip(),
        "author": data.get("author", "").strip(),
        "description": data.get("description", "").strip(),
        "domain": data.get("domain", "").strip(),
        "published": data.get("published", "").strip(),
        "language": data.get("language", "").strip(),
        "word_count": data.get("wordCount", 0),
        "raw": data,
    }


def clean_html(html: str, timeout: int = DEFAULT_TIMEOUT) -> dict:
    """Clean an HTML string. Writes to temp file then calls defuddle."""
    if not html or not html.strip():
        return {"ok": False, "error": "empty html input"}

    with tempfile.NamedTemporaryFile(
        mode="w", suffix=".html", delete=False, encoding="utf-8"
    ) as f:
        f.write(html)
        tmp_path = f.name

    try:
        return _run_defuddle(tmp_path, timeout=timeout)
    finally:
        Path(tmp_path).unlink(missing_ok=True)


def clean_url(url: str, timeout: int = DEFAULT_TIMEOUT) -> dict:
    """Clean a URL directly. defuddle fetches + parses in one shot."""
    if not url or not url.strip():
        return {"ok": False, "error": "empty url input"}
    return _run_defuddle(url.strip(), timeout=timeout)


def token_save_estimate(original_html: str, cleaned_markdown: str) -> dict:
    """Rough char-count ratio for token-save reporting.

    Not exact tokens — but a useful first approximation when running
    A/B comparisons before/after enabling defuddle in a pipeline.
    """
    orig_len = len(original_html or "")
    clean_len = len(cleaned_markdown or "")
    if orig_len == 0:
        return {"orig_chars": 0, "clean_chars": clean_len, "saved_pct": 0.0}
    saved = max(0, orig_len - clean_len)
    return {
        "orig_chars": orig_len,
        "clean_chars": clean_len,
        "saved_pct": round(100.0 * saved / orig_len, 1),
    }


if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("usage: python -m aria_lib.defuddle_clean <url-or-html-file>")
        sys.exit(1)

    arg = sys.argv[1]
    if arg.startswith("http"):
        result = clean_url(arg)
    else:
        result = clean_html(Path(arg).read_text(encoding="utf-8"))

    print(json.dumps(
        {k: v for k, v in result.items() if k != "raw"},
        indent=2,
        ensure_ascii=False,
    ))
