#!/usr/bin/env python3
"""
Adjudica candidatos REVISAR usando `claude -p` (CLI) en lugar de la API directa.
Mismo output que adjudicate_llama.py pero usa la sesión activa de Claude Code.

Uso:
  python3 adjudicate_cli.py --all --only REVISAR
  python3 adjudicate_cli.py --book sri-caitanya-caritamrta
  python3 adjudicate_cli.py --book isopanisad --limit 5  # test
"""
import json, re, sys, argparse, subprocess
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed

HERE = Path(__file__).resolve().parent
CFG = json.loads((HERE / "books.json").read_text())
OCR_DIR = HERE / "ocr"
SURYA_DIR = HERE / "surya"
OUT = HERE / "out"
MAX_WORKERS = 6

def set_out_dir(path):
    global OUT
    OUT = Path(path)
    OUT.mkdir(exist_ok=True)

def page_text(book, pageref):
    if not pageref or "#" not in pageref:
        return ""
    stem, pg = pageref.split("#", 1)
    sp = SURYA_DIR / book / stem / f"{pg}.surya.txt"
    if sp.exists():
        return sp.read_text(errors="ignore")
    tp = OCR_DIR / book / stem / f"{pg}.psm6.txt"
    return tp.read_text(errors="ignore") if tp.exists() else ""

PROMPT = """You are a textual scholar auditing a digital edition (REPO) of an A.C. Bhaktivedanta Swami Prabhupada book. The authority is the ORIGINAL first-edition scan text below.

REPO context — the disputed span is in [[double brackets]]:
{context}

ORIGINAL scan page OCR (may have minor OCR noise like 'l' for 'i'; ignore page numbers/headers):
\"\"\"
{page}
\"\"\"

TASK: Locate the passage in the ORIGINAL that corresponds to the [[bracketed]] span in the REPO.
1. Quote the EXACT words the ORIGINAL uses for that span.
2. Decide: does the ORIGINAL use DIFFERENT WORDS from the REPO (a genuine editorial difference, not a single-character OCR noise substitution like 'l'→'i' or 'e'→'c')?

Answer STRICT JSON only — no prose outside the JSON:
{{"found": true|false, "original_reading": "<exact words from the ORIGINAL for that span>", "is_real_diff": true|false, "confidence": "high|medium|low", "note": "<one sentence: what the original says and why it differs or not>"}}

Rules:
- is_real_diff=true when the ORIGINAL uses a genuinely different word or phrase (e.g. "each other" vs "one another", "instruction" vs "instructions").
- is_real_diff=false only when the ORIGINAL matches the REPO or the only difference is obvious single-character OCR noise (e.g. 'il' for 'il', 'pard' for 'para').
- If you cannot locate the passage, set found=false and is_real_diff=false.
JSON:"""

def call_claude(prompt):
    r = subprocess.run(
        ["claude", "-p", "--output-format", "text", prompt],
        capture_output=True, text=True, timeout=120
    )
    if r.returncode != 0:
        raise RuntimeError(r.stderr[:200])
    return r.stdout.strip()

def parse_json(s):
    m = re.search(r'\{.*\}', s, re.DOTALL)
    if not m:
        return None
    try:
        return json.loads(m.group(0))
    except Exception:
        return None

def apply_consistency_rule(c):
    m = c.get("llm")
    if isinstance(m, dict) and m.get("found") and m.get("original_reading"):
        orig_clean = re.sub(r'[^a-z0-9 ]', '', m["original_reading"].lower()).strip()
        repo_clean = re.sub(r'[^a-z0-9 ]', '', c["repo"].lower()).strip()
        orig_words = set(orig_clean.split())
        repo_words = set(repo_clean.split())
        if len(orig_words) <= 6 and not repo_words.issubset(orig_words) and orig_words != repo_words:
            m["is_real_diff"] = True

def adjudicate_one(c, book):
    page = page_text(book, c.get("page", ""))
    if not page.strip():
        c["llm"] = {"error": "no_page_text"}
        return c
    prompt = PROMPT.format(
        context=c["context"][:1200],
        page=page[:6000]
    )
    try:
        resp = call_claude(prompt)
        c["llm"] = parse_json(resp) or {"raw": resp[:300]}
    except Exception as e:
        c["llm"] = {"error": str(e)[:200]}
    apply_consistency_rule(c)
    return c

def process_book(book, classes, limit=0):
    cf = OUT / f"{book}.candidates.jsonl"
    if not cf.exists():
        return
    cands = [json.loads(l) for l in cf.open()]
    todo = [c for c in cands if c["verdict"] in classes]
    if limit:
        todo = todo[:limit]
    if not todo:
        print(f"{book}: 0 candidates, skipped", file=sys.stderr)
        return

    results = [None] * len(todo)
    n_real = 0
    completed = 0

    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as ex:
        futures = {ex.submit(adjudicate_one, c, book): i for i, c in enumerate(todo)}
        for fut in as_completed(futures):
            i = futures[fut]
            try:
                results[i] = fut.result()
            except Exception as e:
                results[i] = todo[i]
                results[i]["llm"] = {"error": str(e)[:200]}
            completed += 1
            if completed % 10 == 0:
                real_so_far = sum(1 for r in results if r and isinstance(r.get("llm"), dict) and r["llm"].get("is_real_diff"))
                print(f"  {book}: {completed}/{len(todo)} (reales={real_so_far})", file=sys.stderr, flush=True)

    outf = OUT / f"{book}.adjudicated.jsonl"
    with outf.open("w") as fh:
        for r in results:
            if r:
                if isinstance(r.get("llm"), dict) and r["llm"].get("is_real_diff"):
                    n_real += 1
                fh.write(json.dumps(r, ensure_ascii=False) + "\n")
    print(f"{book}: adjudicados {len(todo)}, diffs reales={n_real} -> {outf.name}", file=sys.stderr, flush=True)
    return n_real

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--book")
    ap.add_argument("--all", action="store_true")
    ap.add_argument("--only", default="REVISAR,REPO_TYPO,AMBIGUO")
    ap.add_argument("--limit", type=int, default=0)
    ap.add_argument("--dir", default=None, help="directorio de candidates/adjudicated (default: out/)")
    a = ap.parse_args()
    if a.dir:
        set_out_dir(a.dir)

    classes = set(a.only.split(","))
    books = [a.book] if a.book else list(CFG["books"].keys())

    grand_real = 0
    for book in books:
        r = process_book(book, classes, a.limit)
        if r:
            grand_real += r
    print(f"\nTOTAL diffs reales: {grand_real}", file=sys.stderr)

if __name__ == "__main__":
    main()
