#!/usr/bin/env python3
"""grip_current.py — 1 本の記録 (run のフォルダ) で, 爪を閉じたあとの爪の電流の値を 1 行で出す (2026-11-08 依頼 121).

入力 (run のフォルダ. runs/run_pick_place/{run}/ (教えた動きの再生) でも runs/pi05_policy/{run}/ (実機推論) でもよい):
  recording/currents.csv   gripper_current 列 (依頼 116 の符号付きの値. 爪 7 の番地 69/70)
  recording/states.csv     爪の命令 (gripper_cmd) の時刻. 閉じる命令は grasp_depth.close_time と同じ選び方

見る範囲: 最初に閉じた命令の HELD_FROM_SEC 秒後から, 次に開く命令まで (なければ記録の終わりまで).
  教えた動きの再生では, 閉じてから待ち (2 秒) が終わるまで電流を読まない (依頼 121) ので, 持ち上げてから先の値になる.

目安 (依頼 109・116 の測り. まだ再生の記録では実機で確かめていない):
  空で閉じる: 15 前後 / ブロックをつかむ: 数百〜990 / 放す (開く): −50 前後
  GRASP_LINE (100) 以上なら「つかめていそう」と出す. **目安の表示だけ**で, 学習データから外すかどうかは
  今までどおり grasp_depth.py の深さ (閉じて 1.0 秒後のはみ出し 24px) で決める.

  python3 pi05/grip_current.py RUN_DIR [RUN_DIR ...]
  (grasp_depth.py も同じ run で深さの行の下にこの 1 行を出す)

読むだけ (記録には何も書かない).
"""
import argparse
import csv
import json
import sys
from pathlib import Path

import grasp_depth as gd

GRASP_LINE = 100                # これ以上なら「つかめていそう」(空 15 前後と つかんだ 数百 の間. 目安)
HELD_FROM_SEC = 1.0             # 閉じる命令からこの秒数より後の値を見る (閉じている途中の値を混ぜない)


def summarize(run_dir):
    """戻り値 dict: status (ok / no_currents / no_close / no_values) と, ok なら max・median・n・grasped."""
    rec = Path(run_dir) / "recording"
    out = {"status": None, "max": None, "median": None, "n": 0, "grasped": None,
           "line": GRASP_LINE, "currents_mode": None, "reason": None}
    for name in ("currents_meta.json", "top_meta.json"):
        try:
            out["currents_mode"] = json.loads((rec / name).read_text()).get("currents_mode")
            if out["currents_mode"]:
                break
        except Exception:
            pass
    cur = rec / "currents.csv"
    if not cur.exists():
        out.update(status="no_currents", reason="currents.csv がない (依頼 116・121 より前の記録)")
        return out
    try:
        gt, gs = gd.load_gripper_cmds(rec / "states.csv")
    except Exception as e:
        out.update(status="no_close", reason=f"states.csv を読めない ({type(e).__name__})")
        return out
    t_c = gd.close_time(gt, gs)
    if t_c is None:
        out.update(status="no_close", reason="閉じる命令がない")
        return out
    opens = [float(t) for t, s in zip(gt, gs) if s == 0 and t > t_c]
    t_end = min(opens) if opens else float("inf")
    vals = []
    try:
        with cur.open(newline="") as f:
            for row in csv.DictReader(f):
                try:
                    t, v = float(row["ts"]), row.get("gripper_current") or ""
                except Exception:
                    continue
                if v == "" or not (t_c + HELD_FROM_SEC <= t < t_end):
                    continue
                try:
                    vals.append(int(v))
                except ValueError:
                    continue
    except Exception as e:      # 読めない currents.csv でも 1 行で返す (codex R1 推奨)
        out.update(status="no_values", reason=f"currents.csv を読めない ({type(e).__name__})")
        return out
    out.update(t_close=round(t_c, 3), held_sec=(round(t_end - t_c, 1) if opens else None))
    if not vals:
        out.update(status="no_values",
                   reason="閉じたあとの値がない" + (f" (currents_mode={out['currents_mode']})"
                                                if out["currents_mode"] not in (None, "read_servo") else ""))
        return out
    vs = sorted(vals)
    out.update(status="ok", max=vs[-1], median=vs[len(vs) // 2], n=len(vs), grasped=vs[-1] >= GRASP_LINE)
    return out


def line(run_dir, s=None):
    """表示の 1 行."""
    s = s if s is not None else summarize(run_dir)
    name = Path(run_dir).name
    if s["status"] != "ok":
        return f"[爪 値なし] {name}  {s['reason']}"
    flag = "つかめていそう" if s["grasped"] else "空で閉じた？"
    return (f"[爪 {flag}] {name}  閉じたあとの爪の値 最大 {s['max']} 中央値 {s['median']} ({s['n']} 行) "
            f"(目安の線 {GRASP_LINE}. 空 15 前後・つかむ 数百〜990)")


def main():
    ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
    ap.add_argument("run_dir", nargs="+", help="run のフォルダ (recording/ がある所)")
    args = ap.parse_args()
    for d in args.run_dir:
        print(line(d))
    return 0


if __name__ == "__main__":
    sys.exit(main())
