#!/usr/bin/env python3
"""log450_table.py — 11/6 (Log22) の実機推論9回を, ゲームパッドの補正と推論の実行時間でならべる (LOG450).

使い方: python3 log450_table.py /Volumes/KIOXIA/r2r2r-data/runs/pi05_policy
  - 11/6 の9回: 回ごとの結果・つかんだ推論・離した推論・ゲームパッドの補正 (始めと終わりの実測の差)
  - 推論1回分を実行するのにかかった時間 (t_exec_end - t_exec_start) を 10/31・11/1・11/6 でならべる
元の記録は読むだけ (書かない).
"""
import glob
import json
import statistics as st
import sys
from datetime import datetime
from pathlib import Path

ROOT = Path(sys.argv[1] if len(sys.argv) > 1 else "/Volumes/KIOXIA/r2r2r-data/runs/pi05_policy")


def load(d):
    rows = [json.loads(x) for x in open(d / "log.jsonl", encoding="utf-8")]
    try:
        trial = json.load(open(d / f"{d.name}.json", encoding="utf-8"))
    except FileNotFoundError:
        trial = {}
    return rows, trial


def med(xs):
    return round(st.median(xs), 2) if xs else None


print("## 11/6 の9回 (pi05_20261106_*)\n")
print("| 回 | 記録 | 結果 | 実行した推論 | 爪を閉じた推論 | 爪を開いた推論 | ゲームパッドの補正 (推論 何番のあと: 秒・送った回数・実測の変化) |")
print("|---|---|---|---|---|---|---|")
all_corr = []
for n, d in enumerate(sorted(ROOT.glob("pi05_20261106_*")), 1):
    rows, trial = load(d)
    ex = [r for r in rows if r.get("type") is None and r.get("executed")]
    close = [r["chunk"] for r in ex if r.get("grip_cmd") == 1]
    open_ = [r["chunk"] for r in ex if r.get("grip_cmd") == 0]
    cs = []
    for r in rows:
        if r.get("type") == "correction" and r.get("device") == "gamepad":
            a, b = r["start_pose"], r["measured_after"]
            dj = [(k, b[k] - a[k]) for k in range(5) if abs(b[k] - a[k]) >= 1.0]
            txt = ", ".join(f"j{k} {v:+.1f}°" for k, v in dj) or "変化 1° 未満"
            cs.append(f"推論{r['after_chunk']}: {r['duration_s']:.1f}秒・{r['steps_sent']}回・{txt}")
            all_corr.append({"run": d.name, "after": r["after_chunk"], "dur": r["duration_s"], "sent": r["steps_sent"],
                             "ignored": r.get("pad_ignored"), "dj": dj, "out": r.get("outside_envelope"),
                             "after_close": bool(close) and r["after_chunk"] >= close[0]})
    t0 = datetime.strptime(d.name[5:], "%Y%m%d_%H%M%S").strftime("%H:%M")
    res = {"success": "成功", "failure": "失敗"}.get(trial.get("outcome"), "記録なし")
    print(f"| {n} | {d.name} ({t0}) | {res} | {len(ex)} | {close} | {open_} | {' / '.join(cs)} |")

print("\n## ゲームパッドの補正 (19回)\n")
before = [c for c in all_corr if not c["after_close"]]
after = [c for c in all_corr if c["after_close"]]
for name, cs in (("つかむ前", before), ("つかんだあと", after), ("合わせて", all_corr)):
    ds = [c["dur"] for c in cs]
    print(f"- {name}: {len(cs)}回  かかった時間 中央 {med(ds)}秒・最短 {min(ds):.1f}秒・最長 {max(ds):.1f}秒・合計 {sum(ds):.1f}秒"
          f"  送った回数の中央 {med([c['sent'] for c in cs])}  受付なし 合計 {sum(c['ignored'] or 0 for c in cs)}")
for name, cs in (("つかむ前", before), ("つかんだあと", after)):
    js = {}
    for c in cs:
        for k, v in c["dj"]:
            js.setdefault(k, []).append(v)
    print(f"- {name} に動いた関節: " + ", ".join(f"j{k} {len(v)}回 (中央 {med(v):+.1f}°・{min(v):+.1f}〜{max(v):+.1f}°)"
                                                for k, v in sorted(js.items())))
print("- 学習データの範囲の外で終えた補正: " + (", ".join(f"{c['run']} 推論{c['after']}のあと j{c['out']}" for c in all_corr if c["out"]) or "なし"))

print("\n## 推論1回分を実行するのにかかった時間 (t_exec_end - t_exec_start)\n")
print("| 日 | 記録の数 | 実行した推論 | 中央 | 最短 | 最長 | 中継点4点の推論の中央 |")
print("|---|---|---|---|---|---|---|")
for day in ("20261031", "20261101", "20261106"):
    ds, d4 = [], []
    dirs = sorted(ROOT.glob(f"pi05_{day}_*"))
    for d in dirs:
        rows, _ = load(d)
        for r in rows:
            if r.get("type") is None and r.get("executed") and r.get("t_exec_start"):
                t = r["t_exec_end"] - r["t_exec_start"]
                ds.append(t)
                if len(r.get("sent_targets") or []) == 4 and r.get("grip_cmd") is None:
                    d4.append(t)
    if ds:
        print(f"| {day[4:6]}/{day[6:]} | {len(dirs)} | {len(ds)} | {med(ds)}秒 | {min(ds):.2f}秒 | {max(ds):.2f}秒 | {med(d4)}秒 ({len(d4)}回) |")

print("\n## 1回の補正にかかった時間 (correction の accept 行の t_end - t_start)\n")
print("| 日 | 直し方 | 補正の数 | 中央 | 最短 | 最長 | 合計 |")
print("|---|---|---|---|---|---|---|")
for day in ("20261031", "20261101", "20261106"):
    ds, dev = [], set()
    for d in sorted(ROOT.glob(f"pi05_{day}_*")):
        rows, _ = load(d)
        for r in rows:
            if r.get("type") == "correction" and r.get("action") == "accept":
                ds.append(r["t_end"] - r["t_start"])
                dev.add("ゲームパッド (p)" if r.get("device") == "gamepad" else "キー (c)")
    if ds:
        print(f"| {day[4:6]}/{day[6:]} | {' / '.join(sorted(dev))} | {len(ds)} | {med(ds)}秒 | {min(ds):.1f}秒 | {max(ds):.1f}秒 | {sum(ds):.1f}秒 |")
