"""Shared evaluation harness for OCR-tolerant matching experiments."""

import csv
import sys
from pathlib import Path

DATA_DIR = Path(__file__).parent
CSV_PATH = DATA_DIR / "ocr_errors.csv"
THRESHOLDS = [0.50, 0.60, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95]


def load_pairs():
    """Load (ocr_error, correction) pairs from CSV."""
    pairs = []
    with open(CSV_PATH) as f:
        reader = csv.DictReader(f)
        for row in reader:
            pairs.append((row["ocr_error"], row["correction"]))
    return pairs


def evaluate(score_fn, name="Algorithm", show_failures=10):
    """Run evaluation of a scoring function against all pairs.

    Args:
        score_fn: callable(query, candidate) -> float in [0, 1]
                  query = what user searches for (correction)
                  candidate = what's on the page (ocr_error)
        name: display name for the algorithm
        show_failures: how many worst-scoring pairs to show
    """
    pairs = load_pairs()
    scores = []

    for ocr_error, correction in pairs:
        s = score_fn(correction, ocr_error)
        scores.append((s, ocr_error, correction))

    scores.sort(key=lambda x: x[0])

    # Header
    print(f"\n{'=' * 60}")
    print(f"  {name}")
    print(f"{'=' * 60}")
    print(f"  Pairs: {len(scores)}")
    print(f"  Mean score: {sum(s for s, _, _ in scores) / len(scores):.4f}")
    print(f"  Median score: {scores[len(scores)//2][0]:.4f}")
    print(f"  Min score: {scores[0][0]:.4f}")
    print()

    # Recall at thresholds
    print(f"  {'Threshold':>10}  {'Recall':>8}  {'Matched':>8}  {'Missed':>8}")
    print(f"  {'-'*10}  {'-'*8}  {'-'*8}  {'-'*8}")
    for t in THRESHOLDS:
        matched = sum(1 for s, _, _ in scores if s >= t)
        missed = len(scores) - matched
        recall = matched / len(scores)
        print(f"  {t:>10.2f}  {recall:>8.1%}  {matched:>8}  {missed:>8}")

    # Worst pairs
    if show_failures > 0:
        print(f"\n  Bottom {show_failures} scores:")
        print(f"  {'Score':>7}  {'OCR Error':<25}  {'Correction':<25}")
        print(f"  {'-'*7}  {'-'*25}  {'-'*25}")
        for s, ocr_err, corr in scores[:show_failures]:
            print(f"  {s:>7.4f}  {ocr_err:<25}  {corr:<25}")

    print()
    return scores
