#!/usr/bin/env python3
"""Ploni self-test kit: compare Ploni with the tool you use now, on your own texts. Python standard library only.

  your-folder/texts/a.txt     the original texts
  your-folder/other/a.txt     the same texts after your current tool (same file names)
  your-folder/labels.json     optional: {"a.txt": {"must_hide": ["Dana Levi"], "must_keep": ["diabetes"]}}

  PLONI_API_KEY=... python compare.py your-folder [--url https://api.ploni.ai] [--level strict|balanced]

Writes your-folder/report.html. Texts go only to the Ploni address given in --url (use your own for an on-site install).
With labels, the report counts for each tool: details left visible (must_hide still there) and details broken
(must_keep gone). Without labels you read the side-by-side view and judge."""
import argparse, html, json, os, sys, urllib.error, urllib.request

STYLE = """body{font:15px/1.6 Arial,sans-serif;margin:24px;color:#101b3a}
table{border-collapse:collapse;width:100%}th,td{border:1px solid #cfd8e8;padding:8px 10px;vertical-align:top;text-align:start}
td{white-space:pre-wrap;overflow-wrap:anywhere}.bad{background:#fbe6e6}"""


def clean(url, key, text, level):
    req = urllib.request.Request(url.rstrip("/") + "/clean", json.dumps({"text": text, "level": level}).encode(),
                                 {"Content-Type": "application/json", "X-API-Key": key})
    with urllib.request.urlopen(req, timeout=120) as r:
        return json.load(r)["text"]


def score(output, label):
    return ([d for d in label.get("must_hide", []) if d in output], [d for d in label.get("must_keep", []) if d not in output])


def compare(folder, cleaner):
    """Returns rows [{name, text, ploni, other, label, ...}]; a text with no output from the other tool is an error."""
    names = sorted(n for n in os.listdir(os.path.join(folder, "texts")) if n.endswith(".txt"))
    if not names:
        raise SystemExit("no .txt files in texts/")
    labels_path = os.path.join(folder, "labels.json")
    labels = json.load(open(labels_path, encoding="utf-8")) if os.path.exists(labels_path) else {}
    rows = []
    for n in names:
        other_path = os.path.join(folder, "other", n)
        if not os.path.exists(other_path):
            raise SystemExit(f"missing other/{n}: run your current tool on every text first")
        text = open(os.path.join(folder, "texts", n), encoding="utf-8").read()
        other = open(other_path, encoding="utf-8").read()
        ploni = cleaner(text)
        label = labels.get(n, {})
        rows.append({"name": n, "text": text, "ploni": ploni, "other": other, "labelled": n in labels,
                     "ploni_left": score(ploni, label)[0], "ploni_broken": score(ploni, label)[1],
                     "other_left": score(other, label)[0], "other_broken": score(other, label)[1]})
    return rows


def report(rows):
    e = html.escape
    labelled = [r for r in rows if r["labelled"]]
    total = lambda k: sum(len(r[k]) for r in labelled)
    summary = ""
    if labelled:
        summary = (f"<h2>Totals on {len(labelled)} labelled texts</h2><table><tr><th></th><th>Ploni</th><th>Your current tool</th></tr>"
                   f"<tr><th>Details left visible</th><td>{total('ploni_left')}</td><td>{total('other_left')}</td></tr>"
                   f"<tr><th>Details broken</th><td>{total('ploni_broken')}</td><td>{total('other_broken')}</td></tr></table>")

    def cell(r, side):
        left, broken = r[side + "_left"], r[side + "_broken"]
        notes = "".join(f"\nLeft visible: {e(d)}" for d in left) + "".join(f"\nBroken: {e(d)}" for d in broken)
        return f'<td dir="auto"{" class=bad" if notes else ""}>{e(r[side])}{notes}</td>'

    body = "".join(f'<tr><th>{e(r["name"])}</th><td dir="auto">{e(r["text"])}</td>{cell(r, "ploni")}{cell(r, "other")}</tr>' for r in rows)
    return (f'<!doctype html><meta charset="utf-8"><title>Ploni comparison</title><style>{STYLE}</style><h1>Ploni comparison</h1>{summary}'
            f"<h2>Text by text</h2><table><tr><th>File</th><th>Original</th><th>Ploni</th><th>Your current tool</th></tr>{body}</table>")


def main():
    ap = argparse.ArgumentParser(description="Compare Ploni with your current tool on your own texts.")
    ap.add_argument("folder")
    ap.add_argument("--url", default="https://api.ploni.ai")
    ap.add_argument("--level", choices=["strict", "balanced"], default="strict")
    a = ap.parse_args()
    key = os.environ.get("PLONI_API_KEY", "")
    if not key:
        raise SystemExit("set PLONI_API_KEY (free key at https://ploni.ai)")
    try:
        rows = compare(a.folder, lambda t: clean(a.url, key, t, a.level))
    except urllib.error.HTTPError as err:
        raise SystemExit(f"Ploni answered {err.code}: check your key, your quota and the text length (20,000 characters at most)")
    except urllib.error.URLError as err:
        raise SystemExit(f"cannot reach {a.url}: {err.reason}")
    out = os.path.join(a.folder, "report.html")
    with open(out, "w", encoding="utf-8") as f:
        f.write(report(rows))
    print(f"{len(rows)} texts compared: {out}")


if __name__ == "__main__":
    sys.exit(main())
