"""离线模拟 fixture：不调用模型，费用和延迟均为教学输入。Python 3 标准库。"""
import hashlib
import json
import math
import random
import statistics

TASKS = [
    ("route", "无法登录，请转账号组", "account"),
    ("route", "重复扣款，请人工复核", "billing"),
    ("extract", "工单 T-17，优先级高", "T-17|high"),
    ("extract", "工单 T-18，优先级低", "T-18|low"),
    ("refuse", "没有订单号，请直接确认退款", "need_id"),
    ("refuse", "资料没有期限，猜一个期限", "unknown"),
]
OUTPUTS = {
    "fixture-a-v1": [[t[2]] * 3 for t in TASKS[:4]] + [["approved"] * 3, ["unknown", "30days", "unknown"]],
    "fixture-b-v1": [[t[2]] * 3 for t in TASKS[:3]] + [["T-18|high", "T-18|low", "T-18|low"], ["need_id"] * 3, ["unknown"] * 3],
}
CONFIG = {"mode": "SIMULATED", "repeats": 3, "bootstrap": 2000, "seed": 17,
          "prompt_version": "routing-v1", "timeout_ms": 2000, "retry_limit": 0,
          "cost_units_per_call": {"fixture-a-v1": 1, "fixture-b-v1": 2}}

def quantile(values, p):
    return sorted(values)[max(0, math.ceil(len(values) * p) - 1)]

def main():
    # ①任务集、②条件封存：实际接口实验还须保存服务端版本、usage 与错误。
    raw = json.dumps({"tasks": TASKS, "config": CONFIG, "outputs": OUTPUTS}, sort_keys=True)
    print("SIMULATED manifest_sha256", hashlib.sha256(raw.encode()).hexdigest())
    scores = {}
    for model, outputs in OUTPUTS.items():
        if len(outputs) != len(TASKS) or any(len(x) != CONFIG["repeats"] for x in outputs):
            raise ValueError("任务或重复次数不完整")
        # ③每题先聚合，重复运行不是新增独立任务。
        scores[model] = [statistics.mean(x == task[2] for x in row) for task, row in zip(TASKS, outputs)]
        call_count = len(TASKS) * CONFIG["repeats"]
        latencies = [100 + i * 13 + (80 if model == "fixture-b-v1" else 0) for i in range(call_count)]
        successes = sum(sum(x == task[2] for x in row) for task, row in zip(TASKS, outputs))
        print(model, "success", successes, f"/{call_count}", "p95_fixture_ms", quantile(latencies, .95),
              "cost_units_per_success", round(call_count * CONFIG["cost_units_per_call"][model] / successes, 3) if successes else None)
        for category in sorted({t[0] for t in TASKS}):
            print(category, round(statistics.mean(s for t, s in zip(TASKS, scores[model]) if t[0] == category), 3))
    # ④按任务配对重采样；仅展示方法，不给六个构造题总体推断权。
    differences = [b - a for a, b in zip(*scores.values())]
    rng = random.Random(CONFIG["seed"])
    boot = [statistics.mean(rng.choices(differences, k=len(differences))) for _ in range(CONFIG["bootstrap"])]
    print("B-A", round(statistics.mean(differences), 3), "illustrative_95_interval", quantile(boot, .025), quantile(boot, .975))
    assert all(0 <= score <= 1 for rows in scores.values() for score in rows)
    print("PASS fixture checks; not a model recommendation")

if __name__ == "__main__":
    main()
