"""Exercice fictif de règle d’escalade. Aucun appel de modèle, aucune calibration."""
import csv
import json
from decimal import Decimal, InvalidOperation
from pathlib import Path


def score_value(raw):
    if raw is None or str(raw).strip() == "":
        return None
    try:
        value = Decimal(str(raw))
    except InvalidOperation as exc:
        raise ValueError("score invalide") from exc
    if not value.is_finite() or not Decimal("0") <= value <= Decimal("1"):
        raise ValueError("score hors [0, 1]")
    return value


def route(row, threshold, use_review_rule):
    if use_review_rule and row["review_required"] == "true":
        return "human"
    value = score_value(row.get("score"))
    if value is None:
        return "large"
    return "small" if value >= threshold else "large"


def evaluate(rows, threshold, use_review_rule):
    decisions = [dict(row, destination=route(row, threshold, use_review_rule)) for row in rows]
    kept = [row for row in decisions if row["destination"] == "small"]
    errors = [row["id"] for row in kept if row["prediction"] != row["reference"]]
    return {
        "threshold_inclusive": str(threshold),
        "use_review_rule": use_review_rule,
        "counts": {target: sum(row["destination"] == target for row in decisions)
                   for target in ("small", "large", "human")},
        "kept_correct": len(kept) - len(errors),
        "known_errors_kept": errors,
        "large_model_answers": None,
        "human_answers": None,
        "final_quality": None,
        "actual_cost": None,
        "decisions": decisions,
    }


def main():
    source = Path(__file__).with_name("tickets-fictifs.csv")
    with source.open(newline="", encoding="utf-8") as stream:
        rows = list(csv.DictReader(stream))
    if len({row["id"] for row in rows}) != len(rows):
        raise ValueError("identifiants dupliqués")
    for row in rows:
        score_value(row["score"])
        if row["review_required"] not in ("true", "false"):
            raise ValueError("review_required doit être true ou false")
    sample = {"score": "0.90", "review_required": "false"}
    assert route(sample, Decimal("0.90"), True) == "small"
    assert route(dict(sample, score="0.8999"), Decimal("0.90"), True) == "large"
    assert route(dict(sample, score=""), Decimal("0.90"), True) == "large"
    assert route(dict(sample, score="1", review_required="true"), Decimal("0.90"), True) == "human"
    for bad in ("NaN", "1.01", "texte"):
        try:
            score_value(bad)
        except ValueError:
            pass
        else:
            raise AssertionError("score invalide accepté")
    print(json.dumps({
        "kind": "fictional_policy_exercise_no_model_call",
        "warning": "Textes, prédictions, scores et règles de revue rédigés pour cet exercice. Aucun score calibré, aucune réponse du grand modèle ou d’un humain, aucun coût réel.",
        "rows": len(rows),
        "runtime_checks": 7,
        "policies": [evaluate(rows, Decimal(threshold), guard)
                     for threshold in ("0.90", "0.95", "0.98")
                     for guard in (False, True)],
    }, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
