"""Check saved evidence; optionally replay the eight OCR calls without writing files."""
import argparse
import hashlib
import json
from pathlib import Path
import subprocess
import unicodedata


def sha(path):
    return hashlib.sha256(path.read_bytes()).hexdigest()


def normalized(text):
    return " ".join(unicodedata.normalize("NFC", text).split())


def distance(a, b):
    row = list(range(len(b) + 1))
    for i, char_a in enumerate(a, 1):
        next_row = [i]
        for j, char_b in enumerate(b, 1):
            next_row.append(min(next_row[-1] + 1, row[j] + 1,
                                row[j - 1] + (char_a != char_b)))
        row = next_row
    return row[-1]


parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--models", type=Path,
                    help="Optional directory with pinned Fraktur.traineddata and eng.traineddata")
args = parser.parse_args()
base = Path(__file__).resolve().parent
result = json.loads((base / "results.json").read_text())
config = json.loads((base / "experiment.json").read_text())
assert sha(base / "experiment.json") == result["publicConfigSha256"]
samples = {item["id"]: item["text"] for item in config["samples"]}
report = []
if args.models:
    version = subprocess.check_output(["tesseract", "--version"], text=True).splitlines()[0]
    print(json.dumps({"replayVersion": version, "originalVersion": result["tesseractVersion"]}))
for font in result["fonts"].values():
    assert sha(base / font["path"]) == font["sha256"]
for test in result["tests"]:
    stem = f'{test["sample"]}-{test["font"]}'
    png = base / "samples" / f"{stem}.png"
    source = base / "samples" / f'{test["sample"]}.source.txt'
    raw = base / test["rawFile"]
    assert sha(png) == test["imageSha256"]
    assert sha(source) == test["sourceSha256"]
    assert sha(raw) == test["rawOutputSha256"]
    assert raw.read_text() == test["rawOutput"]
    text = samples[test["sample"]]
    targets = {"exact": normalized(text), "longSFoldedOnly": normalized(text.replace("ſ", "s"))}
    assert targets == test["targets"]
    measured = {key: distance(target, normalized(raw.read_text())) for key, target in targets.items()}
    assert measured == test["editDistances"]
    row = {"sample": test["sample"], "font": test["font"], "model": test["model"],
           "savedEvidenceVerified": True, "editDistances": measured}
    if args.models:
        model = args.models / f'{test["model"]}.traineddata'
        assert sha(model) == test["modelSha256"], "Model does not match pinned source"
        command = ["tesseract", str(png), "stdout", "--tessdata-dir", str(args.models),
                   "-l", test["model"], "--oem", "1", "--psm", "6", "--dpi", "300"]
        run = subprocess.run(command, capture_output=True, timeout=30, check=True)
        row["replayMatchesOriginalBytes"] = run.stdout == raw.read_bytes()
        row["replayDistances"] = {key: distance(target, normalized(run.stdout.decode()))
                                  for key, target in targets.items()}
        assert row["replayMatchesOriginalBytes"], json.dumps(row)
    report.append(row)
assert len(report) == 8
print(json.dumps({"verifiedTests": len(report), "tests": report}, ensure_ascii=False, indent=2))
